From 135f69405804ac9ea73491704be5dfa447a155b0 Mon Sep 17 00:00:00 2001 From: Yang Tse Date: Sun, 28 Aug 2011 01:19:08 +0200 Subject: NTLM: move NTLM core specifics into curl_ntlm_core.[ch] --- lib/curl_ntlm.c | 352 ++++---------------------------------------------------- 1 file changed, 24 insertions(+), 328 deletions(-) (limited to 'lib/curl_ntlm.c') diff --git a/lib/curl_ntlm.c b/lib/curl_ntlm.c index d4f2cc20b..4398d146c 100644 --- a/lib/curl_ntlm.c +++ b/lib/curl_ntlm.c @@ -35,12 +35,6 @@ #ifdef HAVE_UNISTD_H #include #endif -#ifdef HAVE_SYS_WAIT_H -#include -#endif -#ifdef HAVE_SIGNAL_H -#include -#endif #if (defined(NETWARE) && !defined(__NOVELL_LIBC__)) #include @@ -49,7 +43,7 @@ #define BUILDING_CURL_NTLM_C #include "urldata.h" -#include "non-ascii.h" /* for Curl_convert_... prototypes */ +#include "non-ascii.h" #include "sendf.h" #include "select.h" #include "rawstr.h" @@ -87,22 +81,6 @@ #error "OPENSSL_VERSION_NUMBER not defined" #endif -#if OPENSSL_VERSION_NUMBER < 0x00907001L -#define DES_key_schedule des_key_schedule -#define DES_cblock des_cblock -#define DES_set_odd_parity des_set_odd_parity -#define DES_set_key des_set_key -#define DES_ecb_encrypt des_ecb_encrypt - -/* This is how things were done in the old days */ -#define DESKEY(x) x -#define DESKEYARG(x) x -#else -/* Modern version */ -#define DESKEYARG(x) *x -#define DESKEY(x) &x -#endif - #ifdef OPENSSL_NO_MD4 /* This requires MD4, but OpenSSL was compiled without it */ #define USE_NTRESPONSES 0 @@ -134,15 +112,6 @@ # error "Can't compile NTLM support without a crypto library." #endif -/* The last #include file should be: */ -#include "memdebug.h" - -/* Hostname buffer size */ -#define HOSTNAME_MAX 1024 - -/* "NTLMSSP" signature is always in ASCII regardless of the platform */ -#define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50" - #ifndef USE_NTRESPONSES /* Define this to make the type-3 message include the NT response message */ #define USE_NTRESPONSES 1 @@ -152,6 +121,17 @@ #define USE_NTLM2SESSION 1 #endif +#include "curl_ntlm_core.h" + +/* The last #include file should be: */ +#include "memdebug.h" + +/* Hostname buffer size */ +#define HOSTNAME_MAX 1024 + +/* "NTLMSSP" signature is always in ASCII regardless of the platform */ +#define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50" + #define SHORTPAIR(x) ((x) & 0xff), (((x) >> 8) & 0xff) #define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8) & 0xff), \ (((x) >> 16) & 0xff), (((x) >> 24) & 0xff) @@ -229,6 +209,7 @@ static void ntlm_print_flags(FILE *handle, unsigned long flags) static void ntlm_print_hex(FILE *handle, const char *buf, size_t len) { const char *p = buf; + (void)handle; fprintf(stderr, "0x"); while(len-- > 0) fprintf(stderr, "%02.2x", (unsigned int)*p++); @@ -360,293 +341,6 @@ CURLcode Curl_ntlm_decode_type2_message(struct SessionHandle *data, return CURLE_OK; } -#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. - */ -static void setup_des_key(const unsigned char *key_56, - DES_key_schedule DESKEYARG(ks)) -{ - DES_cblock key; - - 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); - - DES_set_odd_parity(&key); - DES_set_key(&key, ks); -} - -#else /* defined(USE_SSLEAY) */ - -/* - * Turns a 56 bit key into the 64 bit, odd parity key. Used by GnuTLS and NSS. - */ -static void extend_key_56_to_64(const unsigned char *key_56, char *key) -{ - 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); -} - -#if 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]; - extend_key_56_to_64(key_56, key); - gcry_cipher_setkey(*des, key, 8); -} - -#elif defined(USE_NSS) - -/* - * Expands a 56 bit key KEY_56 to 64 bit and encrypts 64 bit of data, using - * the expanded key. The caller is responsible for giving 64 bit of valid - * data is IN and (at least) 64 bit large buffer as OUT. - */ -static bool encrypt_des(const unsigned char *in, unsigned char *out, - const unsigned char *key_56) -{ - const CK_MECHANISM_TYPE mech = CKM_DES_ECB; /* DES cipher in ECB mode */ - PK11SlotInfo *slot = NULL; - char key[8]; /* expanded 64 bit key */ - SECItem key_item; - PK11SymKey *symkey = NULL; - SECItem *param = NULL; - PK11Context *ctx = NULL; - int out_len; /* not used, required by NSS */ - bool rv = FALSE; - - /* use internal slot for DES encryption (requires NSS to be initialized) */ - slot = PK11_GetInternalKeySlot(); - if(!slot) - return FALSE; - - /* expand the 56 bit key to 64 bit and wrap by NSS */ - extend_key_56_to_64(key_56, key); - key_item.data = (unsigned char *)key; - key_item.len = /* hard-wired */ 8; - symkey = PK11_ImportSymKey(slot, mech, PK11_OriginUnwrap, CKA_ENCRYPT, - &key_item, NULL); - if(!symkey) - goto fail; - - /* create DES encryption context */ - param = PK11_ParamFromIV(mech, /* no IV in ECB mode */ NULL); - if(!param) - goto fail; - ctx = PK11_CreateContextBySymKey(mech, CKA_ENCRYPT, symkey, param); - if(!ctx) - goto fail; - - /* perform the encryption */ - if(SECSuccess == PK11_CipherOp(ctx, out, &out_len, /* outbuflen */ 8, - (unsigned char *)in, /* inbuflen */ 8) - && SECSuccess == PK11_Finalize(ctx)) - rv = /* all OK */ TRUE; - -fail: - /* cleanup */ - if(ctx) - PK11_DestroyContext(ctx, PR_TRUE); - if(symkey) - PK11_FreeSymKey(symkey); - if(param) - SECITEM_FreeItem(param, PR_TRUE); - PK11_FreeSlot(slot); - return rv; -} - -#endif /* defined(USE_NSS) */ - -#endif /* defined(USE_SSLEAY) */ - - /* - * takes a 21 byte array and treats it as 3 56-bit DES keys. The - * 8 byte plaintext is encrypted with each key and the resulting 24 - * bytes are stored in the results array. - */ -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)); - DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) results, - DESKEY(ks), DES_ENCRYPT); - - setup_des_key(keys + 7, DESKEY(ks)); - DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results + 8), - DESKEY(ks), DES_ENCRYPT); - - setup_des_key(keys + 14, DESKEY(ks)); - DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results + 16), - DESKEY(ks), DES_ENCRYPT); -#elif defined(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); -#elif defined(USE_NSS) - encrypt_des(plaintext, results, keys); - encrypt_des(plaintext, results + 8, keys + 7); - encrypt_des(plaintext, results + 16, keys + 14); -#endif -} - -/* - * Set up lanmanager hashed password - */ -static void mk_lm_hash(struct SessionHandle *data, - const char *password, - unsigned char *lmbuffer /* 21 bytes */) -{ - CURLcode res; - unsigned char pw[14]; - static const unsigned char magic[] = { - 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 /* i.e. KGS!@#$% */ - }; - size_t len = CURLMIN(strlen(password), 14); - - Curl_strntoupper((char *)pw, password, len); - memset(&pw[len], 0, 14 - len); - - /* - * The LanManager hashed password needs to be created using the - * password in the network encoding not the host encoding. - */ - res = Curl_convert_to_network(data, (char *)pw, 14); - if(res) - return; - - { - /* Create LanManager hashed password. */ - -#ifdef USE_SSLEAY - DES_key_schedule ks; - - setup_des_key(pw, DESKEY(ks)); - DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)lmbuffer, - DESKEY(ks), DES_ENCRYPT); - - setup_des_key(pw + 7, DESKEY(ks)); - DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer + 8), - DESKEY(ks), DES_ENCRYPT); -#elif defined(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); -#elif defined(USE_NSS) - encrypt_des(magic, lmbuffer, pw); - encrypt_des(magic, lmbuffer + 8, pw + 7); -#endif - - memset(lmbuffer + 16, 0, 21 - 16); - } -} - -#if USE_NTRESPONSES -static void ascii_to_unicode_le(unsigned char *dest, const char *src, - size_t srclen) -{ - size_t i; - for(i = 0; i < srclen; i++) { - dest[2 * i] = (unsigned char)src[i]; - dest[2 * i + 1] = '\0'; - } -} - -/* - * Set up nt hashed passwords - */ -static CURLcode mk_nt_hash(struct SessionHandle *data, - const char *password, - unsigned char *ntbuffer /* 21 bytes */) -{ - size_t len = strlen(password); - unsigned char *pw = malloc(len * 2); - CURLcode result; - if(!pw) - return CURLE_OUT_OF_MEMORY; - - ascii_to_unicode_le(pw, password, len); - - /* - * The NT hashed password needs to be created using the password in the - * network encoding not the host encoding. - */ - result = Curl_convert_to_network(data, (char *)pw, len * 2); - if(result) - return result; - - { - /* Create NT hashed password. */ -#ifdef USE_SSLEAY - MD4_CTX MD4pw; - MD4_Init(&MD4pw); - MD4_Update(&MD4pw, pw, 2 * len); - MD4_Final(ntbuffer, &MD4pw); -#elif defined(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); -#elif defined(USE_NSS) - Curl_md4it(ntbuffer, pw, 2 * len); -#endif - - memset(ntbuffer + 16, 0, 21 - 16); - } - - free(pw); - - return CURLE_OK; -} -#endif - -#endif - #ifdef USE_WINDOWS_SSPI void Curl_ntlm_sspi_cleanup(struct ntlmdata *ntlm) { @@ -1096,11 +790,12 @@ CURLcode Curl_ntlm_create_type3_message(struct SessionHandle *data, PK11_DestroyContext(MD5pw, PR_TRUE); #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(data, passwdp, ntbuffer) == CURLE_OUT_OF_MEMORY) + /* We shall only use the first 8 bytes of md5sum, but the des + code in Curl_ntlm_core_lm_resp only encrypt the first 8 bytes */ + if(CURLE_OUT_OF_MEMORY == + Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer)) return CURLE_OUT_OF_MEMORY; - lm_resp(ntbuffer, md5sum, ntresp); + Curl_ntlm_core_lm_resp(ntbuffer, md5sum, ntresp); /* End of NTLM2 Session code */ } @@ -1114,15 +809,16 @@ CURLcode Curl_ntlm_create_type3_message(struct SessionHandle *data, unsigned char lmbuffer[0x18]; #if USE_NTRESPONSES - if(mk_nt_hash(data, passwdp, ntbuffer) == CURLE_OUT_OF_MEMORY) + if(CURLE_OUT_OF_MEMORY == + Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer)) return CURLE_OUT_OF_MEMORY; - lm_resp(ntbuffer, &ntlm->nonce[0], ntresp); + Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], ntresp); #endif - mk_lm_hash(data, passwdp, lmbuffer); - lm_resp(lmbuffer, &ntlm->nonce[0], lmresp); + Curl_ntlm_core_mk_lm_hash(data, passwdp, lmbuffer); + Curl_ntlm_core_lm_resp(lmbuffer, &ntlm->nonce[0], lmresp); /* A safer but less compatible alternative is: - * lm_resp(ntbuffer, &ntlm->nonce[0], lmresp); + * Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], lmresp); * See http://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */ } -- cgit v1.2.1