Subject: Re: [libssh2] Introduction, plans, and some pkg-config problems

Re: [libssh2] Introduction, plans, and some pkg-config problems

From: Simon Josefsson <simon_at_josefsson.org>
Date: Tue, 21 Nov 2006 13:12:51 +0100

Sara Golemon <pollita_at_libssh2.org> writes:

>>>> Hello everyone! I'm attempting to port libssh2 to use libgcrypt
>>>> instead of OpenSSL.
>>> While I agree that adding support for libgcrypt would be nice, I'd
>>> really prefer that it didn't replace the existing OpenSSL
>>> dependency. I use libssh2 in a Mac OS X environment, where OpenSSL
>>> comes already installed. The GNU version would be another
>>> dependency I'd have to build and ship with my app. The fact that
>>> it's LGPL will also require bundling a dynamic library, whereas
>>> libssh2 can currently be static-linked.
>>>
>>> Perhaps a generic crypto interface is in order, so we could choose
>>> the library at compile time?
>>
>> I agree that converting would be very bad, but adding the ability to
>> choose is good.
>>
>
> I realize my non-participation the past several months hardly gives me
> much of a vote, but I do want to third this notion. libssh2 needs to
> be buildable without relying on any GPL'd libraries. I know the GPL
> crowd has their banners to wave, but those of us in the BSD camp don't
> cotton to it's viral habits.
>
> There's some abstraction already built in with the crypt-ops and ralted
> methods. We just need to clean the OpenSSL clutter back a layer or two
> (which I noticed some of y'all are already doing) and gcrypt should be
> able to come in cleanly.

My intention is to build an abstraction layer, and have it be used
everywhere in libssh2. Btw, libgcrypt is not licensed under GPL and
doesn't have its viral habits. In any case, I believe whether to use
OpenSSL or libgcrypt should be up to the user. Is this an acceptable
approach?

Has anyone had a chance to look at my patch to fix the first problem
with crypto abstraction? Here is an updated patch against latest CVS.

/Simon

Index: src/crypt.c
===================================================================
RCS file: /cvsroot/libssh2/libssh2/src/crypt.c,v
retrieving revision 1.4
diff -u -p -w -r1.4 crypt.c
--- src/crypt.c 2 Mar 2006 01:10:53 -0000 1.4
+++ src/crypt.c 21 Nov 2006 12:11:37 -0000
@@ -61,15 +61,66 @@ static LIBSSH2_CRYPT_METHOD libssh2_cryp
 };
 #endif
 
+#define MAKE_INIT(name, cipher) \
+ static int name (LIBSSH2_SESSION *session, \
+ unsigned char *iv, int *free_iv, \
+ unsigned char *secret, int *free_secret, \
+ int encrypt, void **abstract) \
+ { \
+ EVP_CIPHER_CTX *ctx = LIBSSH2_ALLOC(session, sizeof(EVP_CIPHER_CTX)); \
+ if (!ctx) \
+ return -1; \
+ EVP_CIPHER_CTX_init(ctx); \
+ EVP_CipherInit(ctx, cipher, secret, iv, encrypt); \
+ *abstract = ctx; \
+ *free_iv = 1; \
+ *free_secret = 1; \
+ return 0; \
+ }
+
+MAKE_INIT(aes256_init, EVP_aes_256_cbc())
+MAKE_INIT(aes192_init, EVP_aes_192_cbc())
+MAKE_INIT(aes128_init, EVP_aes_128_cbc())
+MAKE_INIT(blowfish_init, EVP_bf_cbc())
+MAKE_INIT(arcfour_init, EVP_rc4())
+MAKE_INIT(cast128_init, EVP_cast5_cbc())
+MAKE_INIT(des3_init, EVP_des_ede3_cbc())
+
+int crypt(LIBSSH2_SESSION *session, unsigned char *block, void **abstract)
+{
+ EVP_CIPHER_CTX *ctx = *(EVP_CIPHER_CTX **)abstract;
+ int blocksize = ctx->cipher->block_size;
+ unsigned char buf[EVP_MAX_BLOCK_LENGTH];
+ int ret;
+ if (blocksize == 1) /* Hack for arcfour. */
+ blocksize = 8;
+ ret = EVP_Cipher(ctx, buf, block, blocksize);
+ if (ret == 1)
+ memcpy(block, buf, blocksize);
+ return ret == 1 ? 0 : 1;
+}
+
+int dtor(LIBSSH2_SESSION *session, void **abstract)
+{
+ EVP_CIPHER_CTX **ctx = (EVP_CIPHER_CTX **)abstract;
+ if (ctx && *ctx)
+ {
+ EVP_CIPHER_CTX_cleanup(*ctx);
+ LIBSSH2_FREE(session, *ctx);
+ *abstract = NULL;
+ }
+ return 0;
+}
+
 static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_3des_cbc = {
         "3des-cbc",
         8, /* blocksize */
         8, /* initial value length */
         24, /* secret length */
- LIBSSH2_CRYPT_METHOD_FLAG_EVP,
- NULL,
- (void*)EVP_des_ede3_cbc,
- NULL,
+ 0, /* flags */
+ &des3_init,
+ &crypt,
+ &dtor
 };
 
 #if OPENSSL_VERSION_NUMBER >= 0x00907000L && !defined(OPENSSL_NO_AES)
@@ -78,10 +129,10 @@ static LIBSSH2_CRYPT_METHOD libssh2_cryp
         16, /* blocksize */
         16, /* initial value length */
         16, /* secret length -- 16*8 == 128bit */
- LIBSSH2_CRYPT_METHOD_FLAG_EVP,
- NULL,
- (void*)EVP_aes_128_cbc,
- NULL,
+ 0, /* flags */
+ &aes128_init,
+ &crypt,
+ &dtor
 };
 
 static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes192_cbc = {
@@ -89,10 +140,10 @@ static LIBSSH2_CRYPT_METHOD libssh2_cryp
         16, /* blocksize */
         16, /* initial value length */
         24, /* secret length -- 24*8 == 192bit */
- LIBSSH2_CRYPT_METHOD_FLAG_EVP,
- NULL,
- (void*)EVP_aes_192_cbc,
- NULL,
+ 0, /* flags */
+ &aes192_init,
+ &crypt,
+ &dtor
 };
 
 static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes256_cbc = {
@@ -100,10 +151,10 @@ static LIBSSH2_CRYPT_METHOD libssh2_cryp
         16, /* blocksize */
         16, /* initial value length */
         32, /* secret length -- 32*8 == 256bit */
- LIBSSH2_CRYPT_METHOD_FLAG_EVP,
- NULL,
- (void*)EVP_aes_256_cbc,
- NULL,
+ 0, /* flags */
+ &aes256_init,
+ &crypt,
+ &dtor
 };
 
 /* rijndael-cbc_at_lysator.liu.se == aes256-cbc */
@@ -112,10 +163,10 @@ static LIBSSH2_CRYPT_METHOD libssh2_cryp
         16, /* blocksize */
         16, /* initial value length */
         32, /* secret length -- 32*8 == 256bit */
- LIBSSH2_CRYPT_METHOD_FLAG_EVP,
- NULL,
- (void*)EVP_aes_256_cbc,
- NULL,
+ 0, /* flags */
+ &aes256_init,
+ &crypt,
+ &dtor
 };
 #endif /* OPENSSL_VERSION_NUMBER >= 0x00907000L && !defined(OPENSSL_NO_AES)*/
 
@@ -125,10 +176,10 @@ static LIBSSH2_CRYPT_METHOD libssh2_cryp
         8, /* blocksize */
         8, /* initial value length */
         16, /* secret length */
- LIBSSH2_CRYPT_METHOD_FLAG_EVP,
- NULL,
- (void*)EVP_bf_cbc,
- NULL,
+ 0, /* flags */
+ &blowfish_init,
+ &crypt,
+ &dtor
 };
 #endif /* ! OPENSSL_NO_BLOWFISH */
 
@@ -138,10 +189,10 @@ static LIBSSH2_CRYPT_METHOD libssh2_cryp
         8, /* blocksize */
         8, /* initial value length */
         16, /* secret length */
- LIBSSH2_CRYPT_METHOD_FLAG_EVP,
- NULL,
- (void*)EVP_cast5_cbc,
- NULL,
+ 0, /* flags */
+ &cast128_init,
+ &crypt,
+ &dtor
 };
 #endif /* ! OPENSSL_NO_CAST */
 
@@ -151,10 +202,10 @@ static LIBSSH2_CRYPT_METHOD libssh2_cryp
         8, /* blocksize */
         8, /* initial value length */
         16, /* secret length */
- LIBSSH2_CRYPT_METHOD_FLAG_EVP,
- NULL,
- (void*)EVP_rc4,
- NULL,
+ 0, /* flags */
+ &arcfour_init,
+ &crypt,
+ &dtor
 };
 #endif /* ! OPENSSL_NO_RC4 */
 
Index: src/kex.c
===================================================================
RCS file: /cvsroot/libssh2/libssh2/src/kex.c,v
retrieving revision 1.15
diff -u -p -w -r1.15 kex.c
--- src/kex.c 22 Jun 2006 18:45:29 -0000 1.15
+++ src/kex.c 21 Nov 2006 12:11:38 -0000
@@ -38,7 +38,6 @@
 #include "libssh2_priv.h"
 #include <openssl/bn.h>
 #include <openssl/sha.h>
-#include <openssl/evp.h>
 #include <openssl/rand.h>
 
 /* TODO: Switch this to an inline and handle alloc() failures */
@@ -331,46 +330,24 @@ static int libssh2_kex_method_diffie_hel
 #endif
         }
 
- /* Calculate IV/Secret/Key for each direction */
- if (session->local.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
- if (session->local.crypt_abstract) {
- EVP_CIPHER_CTX_cleanup(session->local.crypt_abstract);
- LIBSSH2_FREE(session, session->local.crypt_abstract);
- session->local.crypt_abstract = NULL;
- }
- } else {
- if (session->local.crypt->dtor) {
                         /* Cleanup any existing cipher */
+ if (session->local.crypt->dtor) {
                         session->local.crypt->dtor(session, &session->local.crypt_abstract);
                 }
- }
 
- if (session->local.crypt->init || (session->local.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP)) {
+ /* Calculate IV/Secret/Key for each direction */
+ if (session->local.crypt->init) {
                 unsigned char *iv = NULL, *secret = NULL;
                 int free_iv = 0, free_secret = 0;
 
                 LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(iv, session->local.crypt->iv_len, "A");
                 LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(secret, session->local.crypt->secret_len, "C");
- if (session->local.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
- EVP_CIPHER *(*get_cipher)(void) = (void*)session->local.crypt->crypt;
- EVP_CIPHER *cipher = get_cipher();
- EVP_CIPHER_CTX *ctx;
-
- ctx = LIBSSH2_ALLOC(session, sizeof(EVP_CIPHER_CTX));
- if (!ctx) {
+ if (session->local.crypt->init(session, iv, &free_iv, secret, &free_secret, 1, &session->local.crypt_abstract)) {
                                 LIBSSH2_FREE(session, iv);
                                 LIBSSH2_FREE(session, secret);
                                 ret = -1;
                                 goto clean_exit;
                         }
- EVP_CIPHER_CTX_init(ctx);
- EVP_CipherInit(ctx, cipher, secret, iv, 1);
- session->local.crypt_abstract = ctx;
- free_iv = 1;
- free_secret = 1;
- } else {
- session->local.crypt->init(session, iv, &free_iv, secret, &free_secret, 1, &session->local.crypt_abstract);
- }
 
                 if (free_iv) {
                         memset(iv, 0, session->local.crypt->iv_len);
@@ -386,45 +363,23 @@ static int libssh2_kex_method_diffie_hel
         _libssh2_debug(session, LIBSSH2_DBG_KEX, "Client to Server IV and Key calculated");
 #endif
 
- if (session->remote.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
- if (session->remote.crypt_abstract) {
- EVP_CIPHER_CTX_cleanup(session->remote.crypt_abstract);
- LIBSSH2_FREE(session, session->remote.crypt_abstract);
- session->remote.crypt_abstract = NULL;
- }
- } else {
                 if (session->remote.crypt->dtor) {
                         /* Cleanup any existing cipher */
                         session->remote.crypt->dtor(session, &session->remote.crypt_abstract);
                 }
- }
 
- if (session->remote.crypt->init || (session->remote.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP)) {
+ if (session->remote.crypt->init) {
                 unsigned char *iv = NULL, *secret = NULL;
                 int free_iv = 0, free_secret = 0;
 
                 LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(iv, session->remote.crypt->iv_len, "B");
                 LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(secret, session->remote.crypt->secret_len, "D");
- if (session->remote.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
- EVP_CIPHER *(*get_cipher)(void) = (void*)session->remote.crypt->crypt;
- EVP_CIPHER *cipher = get_cipher();
- EVP_CIPHER_CTX *ctx;
-
- ctx = LIBSSH2_ALLOC(session, sizeof(EVP_CIPHER_CTX));
- if (!ctx) {
+ if (session->remote.crypt->init(session, iv, &free_iv, secret, &free_secret, 0, &session->remote.crypt_abstract)) {
                                 LIBSSH2_FREE(session, iv);
                                 LIBSSH2_FREE(session, secret);
                                 ret = -1;
                                 goto clean_exit;
                         }
- EVP_CIPHER_CTX_init(ctx);
- EVP_CipherInit(ctx, cipher, secret, iv, 0);
- session->remote.crypt_abstract = ctx;
- free_iv = 1;
- free_secret = 1;
- } else {
- session->remote.crypt->init(session, iv, &free_iv, secret, &free_secret, 0, &session->remote.crypt_abstract);
- }
 
                 if (free_iv) {
                         memset(iv, 0, session->remote.crypt->iv_len);
Index: src/libssh2_priv.h
===================================================================
RCS file: /cvsroot/libssh2/libssh2/src/libssh2_priv.h,v
retrieving revision 1.2
diff -u -p -w -r1.2 libssh2_priv.h
--- src/libssh2_priv.h 20 Nov 2006 22:10:56 -0000 1.2
+++ src/libssh2_priv.h 21 Nov 2006 12:11:38 -0000
@@ -282,12 +282,6 @@ struct _LIBSSH2_HOSTKEY_METHOD {
         int (*dtor)(LIBSSH2_SESSION *session, void **abstract);
 };
 
-/* When FLAG_EVP is set, crypt contains a pointer to an EVP_CIPHER generator and init and dtor are ignored
- * Yes, I know it's a hack.
- */
-
-#define LIBSSH2_CRYPT_METHOD_FLAG_EVP 0x0001
-
 struct _LIBSSH2_CRYPT_METHOD {
         char *name;
 
Index: src/packet.c
===================================================================
RCS file: /cvsroot/libssh2/libssh2/src/packet.c,v
retrieving revision 1.37
diff -u -p -w -r1.37 packet.c
--- src/packet.c 14 Nov 2006 01:30:39 -0000 1.37
+++ src/packet.c 21 Nov 2006 12:11:38 -0000
@@ -41,7 +41,6 @@
 #ifndef WIN32
 #include <unistd.h>
 #endif
-#include <openssl/evp.h>
 #include <openssl/rand.h>
 
 /* Needed for struct iovec on some platforms */
@@ -753,9 +752,6 @@ int libssh2_packet_read(LIBSSH2_SESSION
                 int macstate;
                 int free_payload = 1;
 
- /* Safely ignored in CUSTOM cipher mode */
- EVP_CIPHER_CTX *ctx = (EVP_CIPHER_CTX *)session->remote.crypt_abstract;
-
                 /* Note: If we add any cipher with a blocksize less than 6 we'll need to get more creative with this
                  * For now, all blocksize sizes are 8+
                  */
@@ -779,15 +775,10 @@ int libssh2_packet_read(LIBSSH2_SESSION
                         return (session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) ? 0 : -1;
                 }
 
- if (session->remote.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
- EVP_Cipher(ctx, block + blocksize, block, blocksize);
- memcpy(block, block + blocksize, blocksize);
- } else {
                         if (session->remote.crypt->crypt(session, block, &session->remote.crypt_abstract)) {
                                 libssh2_error(session, LIBSSH2_ERROR_DECRYPT, "Error decrypting packet preamble", 0);
                                 return -1;
                         }
- }
 
                 packet_len = libssh2_ntohu32(block);
                 
@@ -828,17 +819,12 @@ int libssh2_packet_read(LIBSSH2_SESSION
                                 LIBSSH2_FREE(session, payload);
                                 return -1;
                         }
- if (session->remote.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
- EVP_Cipher(ctx, block + blocksize, block, blocksize);
- memcpy(s, block + blocksize, blocksize);
- } else {
                                 if (session->remote.crypt->crypt(session, block, &session->remote.crypt_abstract)) {
                                         libssh2_error(session, LIBSSH2_ERROR_DECRYPT, "Error decrypting packet preamble", 0);
                                         LIBSSH2_FREE(session, payload);
                                         return -1;
                                 }
                                 memcpy(s, block, blocksize);
- }
 
                         s += blocksize;
                 }
@@ -1214,9 +1200,6 @@ int libssh2_packet_write(LIBSSH2_SESSION
                 unsigned char *encbuf, *s;
                 int ret;
 
- /* Safely ignored in CUSTOM cipher mode */
- EVP_CIPHER_CTX *ctx = (EVP_CIPHER_CTX *)session->local.crypt_abstract;
-
                 /* include packet_length(4) itself and room for the hash at the end */
                 encbuf = LIBSSH2_ALLOC(session, 4 + packet_length + session->local.mac->mac_len);
                 if (!encbuf) {
@@ -1240,13 +1223,8 @@ int libssh2_packet_write(LIBSSH2_SESSION
 
                 /* Encrypt data */
                 for(s = encbuf; (s - encbuf) < (4 + packet_length) ; s += session->local.crypt->blocksize) {
- if (session->local.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
- EVP_Cipher(ctx, buf, s, session->local.crypt->blocksize);
- memcpy(s, buf, session->local.crypt->blocksize);
- } else {
                                 session->local.crypt->crypt(session, s, &session->local.crypt_abstract);
                         }
- }
 
                 session->local.seqno++;
 
Index: src/session.c
===================================================================
RCS file: /cvsroot/libssh2/libssh2/src/session.c,v
retrieving revision 1.27
diff -u -p -w -r1.27 session.c
--- src/session.c 17 Apr 2006 02:49:44 -0000 1.27
+++ src/session.c 21 Nov 2006 12:11:38 -0000
@@ -410,17 +410,9 @@ LIBSSH2_API void libssh2_session_free(LI
 
                 /* Client to Server */
                 /* crypt */
- if (session->local.crypt) {
- if (session->local.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
- if (session->local.crypt_abstract) {
- EVP_CIPHER_CTX_cleanup(session->local.crypt_abstract);
- LIBSSH2_FREE(session, session->local.crypt_abstract);
- session->local.crypt_abstract = NULL;
- }
- } else if (session->local.crypt->dtor) {
+ if (session->local.crypt && session->local.crypt->dtor) {
                                 session->local.crypt->dtor(session, &session->local.crypt_abstract);
                         }
- }
                 /* comp */
                 if (session->local.comp && session->local.comp->dtor) {
                         session->local.comp->dtor(session, 1, &session->local.comp_abstract);
@@ -432,17 +424,9 @@ LIBSSH2_API void libssh2_session_free(LI
 
                 /* Server to Client */
                 /* crypt */
- if (session->remote.crypt) {
- if (session->remote.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
- if (session->remote.crypt_abstract) {
- EVP_CIPHER_CTX_cleanup(session->remote.crypt_abstract);
- LIBSSH2_FREE(session, session->remote.crypt_abstract);
- session->remote.crypt_abstract = NULL;
- }
- } else if (session->remote.crypt->dtor) {
+ if (session->remote.crypt && session->remote.crypt->dtor) {
                                 session->remote.crypt->dtor(session, &session->remote.crypt_abstract);
                         }
- }
                 /* comp */
                 if (session->remote.comp && session->remote.comp->dtor) {
                         session->remote.comp->dtor(session, 0, &session->remote.comp_abstract);

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
libssh2-devel mailing list
libssh2-devel_at_lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/libssh2-devel
Received on 2006-11-21