]> granicus.if.org Git - curl/commitdiff
Added support for Digest and NTLM authentication using GnuTLS.
authorDan Fandrich <dan@coneharvesters.com>
Thu, 12 Feb 2009 20:48:40 +0000 (20:48 +0000)
committerDan Fandrich <dan@coneharvesters.com>
Thu, 12 Feb 2009 20:48:40 +0000 (20:48 +0000)
CHANGES
RELEASE-NOTES
configure.ac
docs/FAQ
docs/TODO
lib/gtls.c
lib/gtls.h
lib/http_ntlm.c
lib/md5.c
lib/setup.h

diff --git a/CHANGES b/CHANGES
index 3832faab6ea269b17368a9629693ae6eed578377..17d4039eef320426bdfc402173aced6746248dd2 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -6,6 +6,9 @@
 
                                   Changelog
 
+Daniel Fandrich (12 Feb 2009)
+- Added support for Digest and NTLM authentication using GnuTLS.
+
 Daniel Stenberg (11 Feb 2009)
 - CURLINFO_CONDITION_UNMET was added to allow an application to get to know if
   the condition in the previous request was unmet. This is typically a time
index b1d5263d916454c0fa2ca33d33684f75d088eff2..0661de35cfd94a671dce434427995c2ad1474762 100644 (file)
@@ -20,6 +20,7 @@ This release includes the following changes:
  o Added CURLPROXY_HTTP_1_0 and --proxy1.0
  o Added docs/libcurl/symbols-in-versions
  o Added CURLINFO_CONDITION_UNMET
+ o Added support for Digest and NTLM authentication using GnuTLS
 
 This release includes the following bugfixes:
 
index 0630250048d53f638f0da6d9a67849d50d0e6766..779e0e8b0125e8912e554b447df3d0640d62dfd2 100644 (file)
@@ -2508,7 +2508,7 @@ fi
 if test "x$USE_WINDOWS_SSPI" = "x1"; then
   SUPPORT_FEATURES="$SUPPORT_FEATURES SSPI"
 fi
-if test "x$USE_SSLEAY" = "x1" -o "x$USE_WINDOWS_SSPI" = "x1"; then
+if test "x$USE_SSLEAY" = "x1" -o "x$USE_WINDOWS_SSPI" = "x1" -o "x$USE_GNUTLS" = "x1"; then
   SUPPORT_FEATURES="$SUPPORT_FEATURES NTLM"
 fi
 
index 39fd3bdf7057e6678c9b110f507e88d210468fa9..e3814b3437d5ae43786bb30d346a60fd9e88ca2f 100644 (file)
--- a/docs/FAQ
+++ b/docs/FAQ
@@ -788,7 +788,7 @@ FAQ
 
   This is supported in curl 7.10.6 or later. No earlier curl version knows
   of this magic. Later versions require the OpenSSL or Microsoft Windows 
-  libraries to provide this functionality. Using GnuTLS or NSS libraries will 
+  libraries to provide this functionality. Using the NSS library will 
   not provide NTLM authentication functionality in curl.
 
   NTLM is a Microsoft proprietary protocol. Proprietary formats are evil. You
index d38a4aa7d1c3e0e41b42a7aec97cbf5edd3954ae..a0d8b4c6aa5f0515d68bad7ec04bd39833b1af1b 100644 (file)
--- a/docs/TODO
+++ b/docs/TODO
@@ -328,10 +328,10 @@ to provide the data to send.
 
 8.1 Make NTLM work without OpenSSL functions
 
- Get NTLM working using the functions provided by libgcrypt, since GnuTLS
- already depends on that to function. Not strictly SSL/TLS related, but
- hey... Another option is to get available DES and MD4 source code from the
cryptopp library. They are fine license-wise, but are C++.
+ Get NTLM working using the functions provided by NSS.  Not strictly
+ SSL/TLS related, but hey... Another option is to get available DES and
+ MD4 source code from the cryptopp library. They are fine license-wise,
+ but are C++.
 
 8.2 SSL engine stuff
 
index 53a7400a878110dbbb0d9617e7bbe19d3eb5a8b0..b37edd45f47fb67645ab3c24935daba12b8c2657 100644 (file)
@@ -33,6 +33,7 @@
 #ifdef USE_GNUTLS
 #include <gnutls/gnutls.h>
 #include <gnutls/x509.h>
+#include <gcrypt.h>
 
 #include <string.h>
 #include <stdlib.h>
@@ -777,4 +778,29 @@ size_t Curl_gtls_version(char *buffer, size_t size)
   return snprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL));
 }
 
+static void gtls_seed(struct SessionHandle *data)
+{
+  /* TODO: to a good job seeding the RNG */
+  /* This may involve the gcry_control function and these options: */
+  /* GCRYCTL_SET_RANDOM_SEED_FILE */
+  /* GCRYCTL_SET_RNDEGD_SOCKET */
+}
+
+int Curl_gtls_seed(struct SessionHandle *data)
+{
+  /* we have the "SSL is seeded" boolean static to prevent multiple
+     time-consuming seedings in vain */
+  static bool ssl_seeded = FALSE;
+
+  /* Quickly add a bit of entropy */
+  gcry_fast_random_poll();
+
+  if(!ssl_seeded || data->set.str[STRING_SSL_RANDOM_FILE] ||
+     data->set.str[STRING_SSL_EGDSOCKET]) {
+    gtls_seed(data);
+    ssl_seeded = TRUE;
+  }
+  return 0;
+}
+
 #endif /* USE_GNUTLS */
index 9d8c0723dde5b10aebc4704d0054cffa5cc738e9..661cfef789b911e28398890e1c5ccb82e54b659e 100644 (file)
@@ -47,6 +47,7 @@ ssize_t Curl_gtls_recv(struct connectdata *conn, /* connection data */
 void Curl_gtls_session_free(void *ptr);
 size_t Curl_gtls_version(char *buffer, size_t size);
 int Curl_gtls_shutdown(struct connectdata *conn, int sockindex);
+int Curl_gtls_seed(struct SessionHandle *data);
 
 /* API setup for GnuTLS */
 #define curlssl_init Curl_gtls_init
index 7596472383d80254446fc5d83b0986b8d0ef5cd8..59a2d6924d0d0596687d5cf2f6b446e1e5134152 100644 (file)
@@ -60,7 +60,6 @@
 #include "http_ntlm.h"
 #include "url.h"
 #include "memory.h"
-#include "ssluse.h"
 
 #define _MPRINTF_REPLACE /* use our functions only */
 #include <curl/mprintf.h>
@@ -68,9 +67,8 @@
 /* "NTLMSSP" signature is always in ASCII regardless of the platform */
 #define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50"
 
-#ifndef USE_WINDOWS_SSPI
-
-#  ifdef USE_SSLEAY
+#ifdef USE_SSLEAY
+#include "ssluse.h"
 #    ifdef USE_OPENSSL
 #      include <openssl/des.h>
 #      include <openssl/md4.h>
@@ -84,9 +82,6 @@
 #      include <ssl.h>
 #      include <rand.h>
 #    endif
-#  else
-#    error "Can't compile NTLM support without OpenSSL."
-#  endif
 
 #if OPENSSL_VERSION_NUMBER < 0x00907001L
 #define DES_key_schedule des_key_schedule
 #define DESKEY(x) &x
 #endif
 
-#else
+#elif defined(USE_GNUTLS)
+
+#include "gtls.h"
+#include <gcrypt.h>
+
+#define MD5_DIGEST_LENGTH 16
+#define MD4_DIGEST_LENGTH 16
+
+#elif defined(USE_WINDOWS_SSPI)
 
 #include "curl_sspi.h"
 
+#else
+#    error "Can't compile NTLM support without a crypto library."
 #endif
 
 /* The last #include file should be: */
@@ -314,6 +319,7 @@ CURLntlm Curl_input_ntlm(struct connectdata *conn,
 
 #ifndef USE_WINDOWS_SSPI
 
+#ifdef USE_SSLEAY
 /*
  * Turns a 56 bit key into the 64 bit, odd parity key and sets the key.  The
  * key schedule ks is also set.
@@ -335,6 +341,28 @@ static void setup_des_key(const unsigned char *key_56,
   DES_set_odd_parity(&key);
   DES_set_key(&key, ks);
 }
+#elif defined(USE_GNUTLS)
+
+/*
+ * Turns a 56 bit key into the 64 bit, odd parity key and sets the key.
+ */
+static void setup_des_key(const unsigned char *key_56,
+                         gcry_cipher_hd_t *des)
+{
+  char key[8];
+
+  key[0] = key_56[0];
+  key[1] = (unsigned char)(((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1));
+  key[2] = (unsigned char)(((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2));
+  key[3] = (unsigned char)(((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3));
+  key[4] = (unsigned char)(((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4));
+  key[5] = (unsigned char)(((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5));
+  key[6] = (unsigned char)(((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6));
+  key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF);
+
+  gcry_cipher_setkey(*des, key, 8);
+}
+#endif
 
  /*
   * takes a 21 byte array and treats it as 3 56-bit DES keys. The
@@ -345,6 +373,7 @@ static void lm_resp(const unsigned char *keys,
                     const unsigned char *plaintext,
                     unsigned char *results)
 {
+#ifdef USE_SSLEAY
   DES_key_schedule ks;
 
   setup_des_key(keys, DESKEY(ks));
@@ -358,6 +387,24 @@ static void lm_resp(const unsigned char *keys,
   setup_des_key(keys+14, DESKEY(ks));
   DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+16),
                   DESKEY(ks), DES_ENCRYPT);
+#elif USE_GNUTLS
+  gcry_cipher_hd_t des;
+
+  gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
+  setup_des_key(keys, &des);
+  gcry_cipher_encrypt(des, results, 8, plaintext, 8);
+  gcry_cipher_close(des);
+
+  gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
+  setup_des_key(keys+7, &des);
+  gcry_cipher_encrypt(des, results+8, 8, plaintext, 8);
+  gcry_cipher_close(des);
+
+  gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
+  setup_des_key(keys+14, &des);
+  gcry_cipher_encrypt(des, results+16, 8, plaintext, 8);
+  gcry_cipher_close(des);
+#endif
 }
 
 
@@ -391,6 +438,7 @@ static void mk_lm_hash(struct SessionHandle *data,
   {
     /* Create LanManager hashed password. */
 
+#ifdef USE_SSLEAY
     DES_key_schedule ks;
 
     setup_des_key(pw, DESKEY(ks));
@@ -400,6 +448,19 @@ static void mk_lm_hash(struct SessionHandle *data,
     setup_des_key(pw+7, DESKEY(ks));
     DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer+8),
                     DESKEY(ks), DES_ENCRYPT);
+#elif USE_GNUTLS
+    gcry_cipher_hd_t des;
+
+    gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
+    setup_des_key(pw, &des);
+    gcry_cipher_encrypt(des, lmbuffer, 8, magic, 8);
+    gcry_cipher_close(des);
+
+    gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
+    setup_des_key(pw+7, &des);
+    gcry_cipher_encrypt(des, lmbuffer+8, 8, magic, 8);
+    gcry_cipher_close(des);
+#endif
 
     memset(lmbuffer + 16, 0, 21 - 16);
   }
@@ -443,11 +504,18 @@ static CURLcode mk_nt_hash(struct SessionHandle *data,
 
   {
     /* Create NT hashed password. */
+#ifdef USE_SSLEAY
     MD4_CTX MD4pw;
-
     MD4_Init(&MD4pw);
     MD4_Update(&MD4pw, pw, 2*len);
     MD4_Final(ntbuffer, &MD4pw);
+#elif USE_GNUTLS
+    gcry_md_hd_t MD4pw;
+    gcry_md_open(&MD4pw, GCRY_MD_MD4, 0);
+    gcry_md_write(MD4pw, pw, 2*len);
+    memcpy (ntbuffer, gcry_md_read (MD4pw, 0), MD4_DIGEST_LENGTH);
+    gcry_md_close(MD4pw);
+#endif
 
     memset(ntbuffer + 16, 0, 21 - 16);
   }
@@ -837,12 +905,18 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
       unsigned char ntbuffer[0x18];
       unsigned char tmp[0x18];
       unsigned char md5sum[MD5_DIGEST_LENGTH];
-      MD5_CTX MD5pw;
       unsigned char entropy[8];
 
       /* Need to create 8 bytes random data */
+#ifdef USE_SSLEAY
+      MD5_CTX MD5pw;
       Curl_ossl_seed(conn->data); /* Initiate the seed if not already done */
       RAND_bytes(entropy,8);
+#elif USE_GNUTLS
+      gcry_md_hd_t MD5pw;
+      Curl_gtls_seed(conn->data); /* Initiate the seed if not already done */
+      gcry_randomize(entropy, 8, GCRY_STRONG_RANDOM);
+#endif
 
       /* 8 bytes random data as challenge in lmresp */
       memcpy(lmresp,entropy,8);
@@ -853,9 +927,17 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
       memcpy(tmp,&ntlm->nonce[0],8);
       memcpy(tmp+8,entropy,8);
 
+#ifdef USE_SSLEAY
       MD5_Init(&MD5pw);
       MD5_Update(&MD5pw, tmp, 16);
       MD5_Final(md5sum, &MD5pw);
+#elif USE_GNUTLS
+      gcry_md_open(&MD5pw, GCRY_MD_MD5, 0);
+      gcry_md_write(MD5pw, tmp, MD5_DIGEST_LENGTH);
+      memcpy(md5sum, gcry_md_read (MD5pw, 0), MD5_DIGEST_LENGTH);
+      gcry_md_close(MD5pw);
+#endif
+
       /* We shall only use the first 8 bytes of md5sum,
          but the des code in lm_resp only encrypt the first 8 bytes */
       if(mk_nt_hash(conn->data, passwdp, ntbuffer) == CURLE_OUT_OF_MEMORY)
index 965578004fc2cc159852ab96c47f2a58e50706ea..8f2a38dd1b2dd9f99823b04af1fec0716d25398e 100644 (file)
--- a/lib/md5.c
+++ b/lib/md5.c
 
 #include <string.h>
 
+#include "curl_md5.h"
+
+#ifdef USE_GNUTLS
+
+#include <gcrypt.h>
+
+void Curl_md5it(unsigned char *outbuffer, /* 16 bytes */
+                const unsigned char *input)
+{
+  gcry_md_hd_t ctx;
+  gcry_md_open(&ctx, GCRY_MD_MD5, 0);
+  gcry_md_write(ctx, input, (unsigned int)strlen((char *)input));
+  memcpy (outbuffer, gcry_md_read (ctx, 0), 16);
+  gcry_md_close(ctx);
+}
+
+#else
+
 #ifdef USE_SSLEAY
 /* When OpenSSL is available we use the MD5-function from OpenSSL */
 
@@ -341,8 +359,6 @@ static void Decode (UINT4 *output,
 
 #endif /* USE_SSLEAY */
 
-#include "curl_md5.h"
-
 void Curl_md5it(unsigned char *outbuffer, /* 16 bytes */
                 const unsigned char *input)
 {
@@ -352,4 +368,6 @@ void Curl_md5it(unsigned char *outbuffer, /* 16 bytes */
   MD5_Final(outbuffer, &ctx);
 }
 
-#endif
+#endif /* USE_GNUTLS */
+
+#endif /* CURL_DISABLE_CRYPTO_AUTH */
index 5b675edda58b4cad512f29a244b0dde4e718fd5f..efab2ea6fe3710f97e6fbe6cd14fa09252e426c1 100644 (file)
@@ -455,7 +455,7 @@ int netware_init(void);
 #endif
 
 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_NTLM)
-#if defined(USE_SSLEAY) || defined(USE_WINDOWS_SSPI)
+#if defined(USE_SSLEAY) || defined(USE_WINDOWS_SSPI) || defined(USE_GNUTLS)
 #define USE_NTLM
 #endif
 #endif