Added support for Digest and NTLM authentication using GnuTLS.

This commit is contained in:
Dan Fandrich 2009-02-12 20:48:40 +00:00
parent de41c6ef43
commit 9a4c887c4a
10 changed files with 151 additions and 20 deletions

View File

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

View 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:

View 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

View File

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

View File

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

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

View 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

View 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
@ -104,10 +99,20 @@
#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)

View File

@ -27,6 +27,24 @@
#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 */

View 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