aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorKamil Dudka <kdudka@redhat.com>2010-06-27 03:38:01 +0200
committerKamil Dudka <kdudka@redhat.com>2010-06-30 13:12:25 +0200
commitf3b77e5611d860739c0cffbc394172adf1f14b57 (patch)
tree8715c80457ba55d2af77c2f6b11be521857e4ee9 /lib
parent89924a897d1cdb76750459a07e6caf460601c822 (diff)
http_ntlm: add support for NSS
When configured with '--without-ssl --with-nss', NTLM authentication now uses NSS crypto library for MD5 and DES. For MD4 we have a local implementation in that case. More details are available at https://bugzilla.redhat.com/603783 In order to get it working, curl_global_init() must be called with CURL_GLOBAL_SSL or CURL_GLOBAL_ALL. That's necessary because NSS needs to be initialized globally and we do so only when the NSS library is actually required by protocol. The mentioned call of curl_global_init() is responsible for creating of the initialization mutex. There was also slightly changed the NSS initialization scenario, in particular, loading of the NSS PEM module. It used to be loaded always right after the NSS library was initialized. Now the library is initialized as soon as any SSL or NTLM is required, while the PEM module is prevented from being loaded until the SSL is actually required.
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile.inc4
-rw-r--r--lib/curl_md4.h33
-rw-r--r--lib/http_ntlm.c126
-rw-r--r--lib/md4.c281
-rw-r--r--lib/nss.c162
-rw-r--r--lib/nssg.h3
-rw-r--r--lib/setup.h2
7 files changed, 534 insertions, 77 deletions
diff --git a/lib/Makefile.inc b/lib/Makefile.inc
index 63117803d..a502e8f73 100644
--- a/lib/Makefile.inc
+++ b/lib/Makefile.inc
@@ -6,7 +6,7 @@ CSOURCES = file.c timeval.c base64.c hostip.c progress.c formdata.c \
netrc.c getinfo.c transfer.c strequal.c easy.c security.c krb4.c \
curl_fnmatch.c fileinfo.c ftplistparser.c wildcard.c \
krb5.c memdebug.c http_chunks.c strtok.c connect.c llist.c hash.c \
- multi.c content_encoding.c share.c http_digest.c md5.c curl_rand.c \
+ multi.c content_encoding.c share.c http_digest.c md4.c md5.c curl_rand.c \
http_negotiate.c http_ntlm.c inet_pton.c strtoofft.c strerror.c \
hostares.c hostasyn.c hostip4.c hostip6.c hostsyn.c hostthre.c \
inet_ntop.c parsedate.c select.c gtls.c sslgen.c tftp.c splay.c \
@@ -20,7 +20,7 @@ HHEADERS = arpa_telnet.h netrc.h file.h timeval.h qssl.h hostip.h \
if2ip.h speedcheck.h urldata.h curl_ldap.h ssluse.h escape.h telnet.h \
getinfo.h strequal.h krb4.h memdebug.h http_chunks.h curl_rand.h \
curl_fnmatch.h wildcard.h fileinfo.h ftplistparser.h \
- strtok.h connect.h llist.h hash.h content_encoding.h share.h \
+ strtok.h connect.h llist.h hash.h content_encoding.h share.h curl_md4.h \
curl_md5.h http_digest.h http_negotiate.h http_ntlm.h inet_pton.h \
strtoofft.h strerror.h inet_ntop.h curlx.h curl_memory.h setup.h \
transfer.h select.h easyif.h multiif.h parsedate.h sslgen.h gtls.h \
diff --git a/lib/curl_md4.h b/lib/curl_md4.h
new file mode 100644
index 000000000..6b6c16e13
--- /dev/null
+++ b/lib/curl_md4.h
@@ -0,0 +1,33 @@
+#ifndef HEADER_CURL_MD4_H
+#define HEADER_CURL_MD4_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "setup.h"
+
+/* NSS crypto library does not provide the MD4 hash algorithm, so that we have
+ * a local implementation of it */
+#ifdef USE_NSS
+void Curl_md4it(unsigned char *output, const unsigned char *input, size_t len);
+#endif /* USE_NSS */
+
+#endif /* HEADER_CURL_MD4_H */
diff --git a/lib/http_ntlm.c b/lib/http_ntlm.c
index 36e538ea0..0e831ca33 100644
--- a/lib/http_ntlm.c
+++ b/lib/http_ntlm.c
@@ -116,6 +116,15 @@
#define MD5_DIGEST_LENGTH 16
#define MD4_DIGEST_LENGTH 16
+#elif defined(USE_NSS)
+
+#include "curl_md4.h"
+#include "nssg.h"
+#include <nss.h>
+#include <pk11pub.h>
+#include <hasht.h>
+#define MD5_DIGEST_LENGTH MD5_LENGTH
+
#elif defined(USE_WINDOWS_SSPI)
#include "curl_sspi.h"
@@ -250,6 +259,11 @@ CURLntlm Curl_input_ntlm(struct connectdata *conn,
static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 };
#endif
+#ifdef USE_NSS
+ if(CURLE_OK != Curl_nss_force_init(conn->data))
+ return CURLNTLM_BAD;
+#endif
+
ntlm = proxy?&conn->proxyntlm:&conn->ntlm;
/* skip initial whitespaces */
@@ -351,16 +365,14 @@ static void setup_des_key(const unsigned char *key_56,
DES_set_odd_parity(&key);
DES_set_key(&key, ks);
}
-#elif defined(USE_GNUTLS)
+
+#else /* defined(USE_SSLEAY) */
/*
- * Turns a 56 bit key into the 64 bit, odd parity key and sets the key.
+ * Turns a 56 bit key into the 64 bit, odd parity key. Used by GnuTLS and NSS.
*/
-static void setup_des_key(const unsigned char *key_56,
- gcry_cipher_hd_t *des)
+static void extend_key_56_to_64(const unsigned char *key_56, char *key)
{
- 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));
@@ -369,10 +381,84 @@ static void setup_des_key(const unsigned char *key_56,
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);
}
-#endif
+
+#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
@@ -414,6 +500,10 @@ static void lm_resp(const unsigned char *keys,
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
}
@@ -470,11 +560,14 @@ static void mk_lm_hash(struct SessionHandle *data,
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,
@@ -525,6 +618,8 @@ static CURLcode mk_nt_hash(struct SessionHandle *data,
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);
@@ -599,6 +694,11 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
DEBUGASSERT(conn);
DEBUGASSERT(conn->data);
+#ifdef USE_NSS
+ if(CURLE_OK != Curl_nss_force_init(conn->data))
+ return CURLE_OUT_OF_MEMORY;
+#endif
+
if(proxy) {
allocuserpwd = &conn->allocptr.proxyuserpwd;
userp = conn->proxyuser;
@@ -926,6 +1026,11 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
gcry_md_hd_t MD5pw;
Curl_gtls_seed(conn->data); /* Initiate the seed if not already done */
gcry_randomize(entropy, 8, GCRY_STRONG_RANDOM);
+#elif defined(USE_NSS)
+ PK11Context *MD5pw;
+ unsigned int outlen;
+ Curl_nss_seed(conn->data); /* Initiate the seed if not already done */
+ PK11_GenerateRandom(entropy, 8);
#endif
/* 8 bytes random data as challenge in lmresp */
@@ -946,6 +1051,11 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
gcry_md_write(MD5pw, tmp, MD5_DIGEST_LENGTH);
memcpy(md5sum, gcry_md_read (MD5pw, 0), MD5_DIGEST_LENGTH);
gcry_md_close(MD5pw);
+#elif defined(USE_NSS)
+ MD5pw = PK11_CreateDigestContext(SEC_OID_MD5);
+ PK11_DigestOp(MD5pw, tmp, 16);
+ PK11_DigestFinal(MD5pw, md5sum, &outlen, MD5_DIGEST_LENGTH);
+ PK11_DestroyContext(MD5pw, PR_TRUE);
#endif
/* We shall only use the first 8 bytes of md5sum,
diff --git a/lib/md4.c b/lib/md4.c
new file mode 100644
index 000000000..700008375
--- /dev/null
+++ b/lib/md4.c
@@ -0,0 +1,281 @@
+/*-
+ Copyright (C) 1990-2, RSA Data Security, Inc. All rights reserved.
+
+ License to copy and use this software is granted provided that it
+ is identified as the "RSA Data Security, Inc. MD4 Message-Digest
+ Algorithm" in all material mentioning or referencing this software
+ or this function.
+
+ License is also granted to make and use derivative works provided
+ that such works are identified as "derived from the RSA Data
+ Security, Inc. MD4 Message-Digest Algorithm" in all material
+ mentioning or referencing the derived work.
+
+ RSA Data Security, Inc. makes no representations concerning either
+ the merchantability of this software or the suitability of this
+ software for any particular purpose. It is provided "as is"
+ without express or implied warranty of any kind.
+
+ These notices must be retained in any copies of any part of this
+ documentation and/or software.
+ */
+
+#include "setup.h"
+
+/* NSS crypto library does not provide the MD4 hash algorithm, so that we have
+ * a local implementation of it */
+#ifdef USE_NSS
+
+#include "curl_md4.h"
+#include <string.h>
+
+typedef unsigned int UINT4;
+
+typedef struct MD4Context {
+ UINT4 state[4]; /* state (ABCD) */
+ UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ unsigned char buffer[64]; /* input buffer */
+} MD4_CTX;
+
+/* Constants for MD4Transform routine.
+ */
+#define S11 3
+#define S12 7
+#define S13 11
+#define S14 19
+#define S21 3
+#define S22 5
+#define S23 9
+#define S24 13
+#define S31 3
+#define S32 9
+#define S33 11
+#define S34 15
+
+static void MD4Transform(UINT4 [4], const unsigned char [64]);
+static void Encode(unsigned char *, UINT4 *, unsigned int);
+static void Decode(UINT4 *, const unsigned char *, unsigned int);
+
+static unsigned char PADDING[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G and H are basic MD4 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG and HH are transformations for rounds 1, 2 and 3 */
+/* Rotation is separate from addition to prevent recomputation */
+#define FF(a, b, c, d, x, s) { \
+ (a) += F ((b), (c), (d)) + (x); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ }
+#define GG(a, b, c, d, x, s) { \
+ (a) += G ((b), (c), (d)) + (x) + (UINT4)0x5a827999; \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ }
+#define HH(a, b, c, d, x, s) { \
+ (a) += H ((b), (c), (d)) + (x) + (UINT4)0x6ed9eba1; \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ }
+
+/* MD4 initialization. Begins an MD4 operation, writing a new context.
+ */
+static void MD4Init(MD4_CTX *context)
+{
+ context->count[0] = context->count[1] = 0;
+
+ /* Load magic initialization constants.
+ */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xefcdab89;
+ context->state[2] = 0x98badcfe;
+ context->state[3] = 0x10325476;
+}
+
+/* MD4 block update operation. Continues an MD4 message-digest
+ operation, processing another message block, and updating the
+ context.
+ */
+static void MD4Update(MD4_CTX *context, const unsigned char *input,
+ unsigned int inputLen)
+{
+ unsigned int i, bufindex, partLen;
+
+ /* Compute number of bytes mod 64 */
+ bufindex = (unsigned int)((context->count[0] >> 3) & 0x3F);
+ /* Update number of bits */
+ if ((context->count[0] += ((UINT4)inputLen << 3))
+ < ((UINT4)inputLen << 3))
+ context->count[1]++;
+ context->count[1] += ((UINT4)inputLen >> 29);
+
+ partLen = 64 - bufindex;
+ /* Transform as many times as possible.
+ */
+ if (inputLen >= partLen) {
+ bcopy(input, &context->buffer[bufindex], partLen);
+ MD4Transform (context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ MD4Transform (context->state, &input[i]);
+
+ bufindex = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ bcopy(&input[i], &context->buffer[bufindex], inputLen-i);
+}
+
+/* MD4 padding. */
+static void MD4Pad(MD4_CTX *context)
+{
+ unsigned char bits[8];
+ unsigned int bufindex, padLen;
+
+ /* Save number of bits */
+ Encode (bits, context->count, 8);
+
+ /* Pad out to 56 mod 64.
+ */
+ bufindex = (unsigned int)((context->count[0] >> 3) & 0x3f);
+ padLen = (bufindex < 56) ? (56 - bufindex) : (120 - bufindex);
+ MD4Update (context, PADDING, padLen);
+
+ /* Append length (before padding) */
+ MD4Update (context, bits, 8);
+}
+
+/* MD4 finalization. Ends an MD4 message-digest operation, writing the
+ the message digest and zeroizing the context.
+ */
+static void MD4Final (unsigned char digest[16], MD4_CTX *context)
+{
+ /* Do padding */
+ MD4Pad (context);
+
+ /* Store state in digest */
+ Encode (digest, context->state, 16);
+
+ /* Zeroize sensitive information.
+ */
+ memset(context, 0, sizeof(*context));
+}
+
+/* MD4 basic transformation. Transforms state based on block.
+ */
+static void MD4Transform (UINT4 state[4], const unsigned char block[64])
+{
+ UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ Decode (x, block, 64);
+
+ /* Round 1 */
+ FF (a, b, c, d, x[ 0], S11); /* 1 */
+ FF (d, a, b, c, x[ 1], S12); /* 2 */
+ FF (c, d, a, b, x[ 2], S13); /* 3 */
+ FF (b, c, d, a, x[ 3], S14); /* 4 */
+ FF (a, b, c, d, x[ 4], S11); /* 5 */
+ FF (d, a, b, c, x[ 5], S12); /* 6 */
+ FF (c, d, a, b, x[ 6], S13); /* 7 */
+ FF (b, c, d, a, x[ 7], S14); /* 8 */
+ FF (a, b, c, d, x[ 8], S11); /* 9 */
+ FF (d, a, b, c, x[ 9], S12); /* 10 */
+ FF (c, d, a, b, x[10], S13); /* 11 */
+ FF (b, c, d, a, x[11], S14); /* 12 */
+ FF (a, b, c, d, x[12], S11); /* 13 */
+ FF (d, a, b, c, x[13], S12); /* 14 */
+ FF (c, d, a, b, x[14], S13); /* 15 */
+ FF (b, c, d, a, x[15], S14); /* 16 */
+
+ /* Round 2 */
+ GG (a, b, c, d, x[ 0], S21); /* 17 */
+ GG (d, a, b, c, x[ 4], S22); /* 18 */
+ GG (c, d, a, b, x[ 8], S23); /* 19 */
+ GG (b, c, d, a, x[12], S24); /* 20 */
+ GG (a, b, c, d, x[ 1], S21); /* 21 */
+ GG (d, a, b, c, x[ 5], S22); /* 22 */
+ GG (c, d, a, b, x[ 9], S23); /* 23 */
+ GG (b, c, d, a, x[13], S24); /* 24 */
+ GG (a, b, c, d, x[ 2], S21); /* 25 */
+ GG (d, a, b, c, x[ 6], S22); /* 26 */
+ GG (c, d, a, b, x[10], S23); /* 27 */
+ GG (b, c, d, a, x[14], S24); /* 28 */
+ GG (a, b, c, d, x[ 3], S21); /* 29 */
+ GG (d, a, b, c, x[ 7], S22); /* 30 */
+ GG (c, d, a, b, x[11], S23); /* 31 */
+ GG (b, c, d, a, x[15], S24); /* 32 */
+
+ /* Round 3 */
+ HH (a, b, c, d, x[ 0], S31); /* 33 */
+ HH (d, a, b, c, x[ 8], S32); /* 34 */
+ HH (c, d, a, b, x[ 4], S33); /* 35 */
+ HH (b, c, d, a, x[12], S34); /* 36 */
+ HH (a, b, c, d, x[ 2], S31); /* 37 */
+ HH (d, a, b, c, x[10], S32); /* 38 */
+ HH (c, d, a, b, x[ 6], S33); /* 39 */
+ HH (b, c, d, a, x[14], S34); /* 40 */
+ HH (a, b, c, d, x[ 1], S31); /* 41 */
+ HH (d, a, b, c, x[ 9], S32); /* 42 */
+ HH (c, d, a, b, x[ 5], S33); /* 43 */
+ HH (b, c, d, a, x[13], S34); /* 44 */
+ HH (a, b, c, d, x[ 3], S31); /* 45 */
+ HH (d, a, b, c, x[11], S32); /* 46 */
+ HH (c, d, a, b, x[ 7], S33); /* 47 */
+ HH (b, c, d, a, x[15], S34); /* 48 */
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ /* Zeroize sensitive information.
+ */
+ memset(x, 0, sizeof(x));
+}
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+ a multiple of 4.
+ */
+static void Encode(unsigned char *output, UINT4 *input, unsigned int len)
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (unsigned char)(input[i] & 0xff);
+ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+ }
+}
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+ a multiple of 4.
+ */
+static void Decode (UINT4 *output, const unsigned char *input, unsigned int len)
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
+ (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
+
+void Curl_md4it(unsigned char *output, const unsigned char *input, size_t len)
+{
+ MD4_CTX ctx;
+ MD4Init(&ctx);
+ MD4Update(&ctx, input, (unsigned int)len);
+ MD4Final(output, &ctx);
+}
+#endif /* USE_NSS */
diff --git a/lib/nss.c b/lib/nss.c
index 4058d7867..6d3f12c03 100644
--- a/lib/nss.c
+++ b/lib/nss.c
@@ -891,6 +891,57 @@ isTLSIntoleranceError(PRInt32 err)
}
}
+static CURLcode init_nss(struct SessionHandle *data)
+{
+ char *cert_dir;
+ struct_stat st;
+ if(initialized)
+ return CURLE_OK;
+
+ /* First we check if $SSL_DIR points to a valid dir */
+ cert_dir = getenv("SSL_DIR");
+ if(cert_dir) {
+ if((stat(cert_dir, &st) != 0) ||
+ (!S_ISDIR(st.st_mode))) {
+ cert_dir = NULL;
+ }
+ }
+
+ /* Now we check if the default location is a valid dir */
+ if(!cert_dir) {
+ if((stat(SSL_DIR, &st) == 0) &&
+ (S_ISDIR(st.st_mode))) {
+ cert_dir = (char *)SSL_DIR;
+ }
+ }
+
+ if(!NSS_IsInitialized()) {
+ SECStatus rv;
+ initialized = 1;
+ infof(data, "Initializing NSS with certpath: %s\n",
+ cert_dir ? cert_dir : "none");
+ if(!cert_dir) {
+ rv = NSS_NoDB_Init(NULL);
+ }
+ else {
+ char *certpath =
+ PR_smprintf("%s%s", NSS_VersionCheck("3.12.0") ? "sql:" : "", cert_dir);
+ rv = NSS_Initialize(certpath, "", "", "", NSS_INIT_READONLY);
+ PR_smprintf_free(certpath);
+ }
+ if(rv != SECSuccess) {
+ infof(data, "Unable to initialize NSS database\n");
+ initialized = 0;
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+ }
+
+ if(num_enabled_ciphers() == 0)
+ NSS_SetDomesticPolicy();
+
+ return CURLE_OK;
+}
+
/**
* Global SSL init
*
@@ -911,6 +962,21 @@ int Curl_nss_init(void)
return 1;
}
+CURLcode Curl_nss_force_init(struct SessionHandle *data)
+{
+ CURLcode rv;
+ if(!nss_initlock) {
+ failf(data, "unable to initialize NSS, curl_global_init() should have been "
+ "called with CURL_GLOBAL_SSL or CURL_GLOBAL_ALL");
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ PR_Lock(nss_initlock);
+ rv = init_nss(data);
+ PR_Unlock(nss_initlock);
+ return rv;
+}
+
/* Global cleanup */
void Curl_nss_cleanup(void)
{
@@ -1039,16 +1105,12 @@ CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
struct SessionHandle *data = conn->data;
curl_socket_t sockfd = conn->sock[sockindex];
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- SECStatus rv;
- char *certDir = NULL;
int curlerr;
const int *cipher_to_enable;
PRSocketOptionData sock_opt;
long time_left;
PRUint32 timeout;
- curlerr = CURLE_SSL_CONNECT_ERROR;
-
if (connssl->state == ssl_connection_complete)
return CURLE_OK;
@@ -1062,76 +1124,36 @@ CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
/* FIXME. NSS doesn't support multiple databases open at the same time. */
PR_Lock(nss_initlock);
- if(!initialized) {
- struct_stat st;
-
- /* First we check if $SSL_DIR points to a valid dir */
- certDir = getenv("SSL_DIR");
- if(certDir) {
- if((stat(certDir, &st) != 0) ||
- (!S_ISDIR(st.st_mode))) {
- certDir = NULL;
- }
- }
-
- /* Now we check if the default location is a valid dir */
- if(!certDir) {
- if((stat(SSL_DIR, &st) == 0) &&
- (S_ISDIR(st.st_mode))) {
- certDir = (char *)SSL_DIR;
- }
- }
-
- if (!NSS_IsInitialized()) {
- initialized = 1;
- infof(conn->data, "Initializing NSS with certpath: %s\n",
- certDir ? certDir : "none");
- if(!certDir) {
- rv = NSS_NoDB_Init(NULL);
- }
- else {
- char *certpath = PR_smprintf("%s%s",
- NSS_VersionCheck("3.12.0") ? "sql:" : "",
- certDir);
- rv = NSS_Initialize(certpath, "", "", "", NSS_INIT_READONLY);
- PR_smprintf_free(certpath);
- }
- if(rv != SECSuccess) {
- infof(conn->data, "Unable to initialize NSS database\n");
- curlerr = CURLE_SSL_CACERT_BADFILE;
- initialized = 0;
- PR_Unlock(nss_initlock);
- goto error;
- }
- }
+ curlerr = init_nss(conn->data);
+ if(CURLE_OK != curlerr) {
+ PR_Unlock(nss_initlock);
+ goto error;
+ }
- if(num_enabled_ciphers() == 0)
- NSS_SetDomesticPolicy();
+ curlerr = CURLE_SSL_CONNECT_ERROR;
#ifdef HAVE_PK11_CREATEGENERICOBJECT
- if(!mod) {
- char *configstring = aprintf("library=%s name=PEM", pem_library);
- if(!configstring) {
- PR_Unlock(nss_initlock);
- goto error;
- }
- mod = SECMOD_LoadUserModule(configstring, NULL, PR_FALSE);
- free(configstring);
+ if(!mod) {
+ char *configstring = aprintf("library=%s name=PEM", pem_library);
+ if(!configstring) {
+ PR_Unlock(nss_initlock);
+ goto error;
+ }
+ mod = SECMOD_LoadUserModule(configstring, NULL, PR_FALSE);
+ free(configstring);
- if(!mod || !mod->loaded) {
- if(mod) {
- SECMOD_DestroyModule(mod);
- mod = NULL;
- }
- infof(data, "WARNING: failed to load NSS PEM library %s. Using "
- "OpenSSL PEM certificates will not work.\n", pem_library);
+ if(!mod || !mod->loaded) {
+ if(mod) {
+ SECMOD_DestroyModule(mod);
+ mod = NULL;
}
+ infof(data, "WARNING: failed to load NSS PEM library %s. Using "
+ "OpenSSL PEM certificates will not work.\n", pem_library);
}
+ }
#endif
- PK11_SetPasswordFunc(nss_get_password);
-
- }
+ PK11_SetPasswordFunc(nss_get_password);
PR_Unlock(nss_initlock);
model = PR_NewTCPSocket();
@@ -1448,4 +1470,12 @@ size_t Curl_nss_version(char *buffer, size_t size)
{
return snprintf(buffer, size, "NSS/%s", NSS_VERSION);
}
+
+int Curl_nss_seed(struct SessionHandle *data)
+{
+ /* TODO: implement? */
+ (void) data;
+ return 0;
+}
+
#endif /* USE_NSS */
diff --git a/lib/nssg.h b/lib/nssg.h
index 6eaa17858..f9cc46ae2 100644
--- a/lib/nssg.h
+++ b/lib/nssg.h
@@ -46,6 +46,9 @@ size_t Curl_nss_version(char *buffer, size_t size);
int Curl_nss_check_cxn(struct connectdata *cxn);
int Curl_nss_seed(struct SessionHandle *data);
+/* initialize NSS library if not already */
+CURLcode Curl_nss_force_init(struct SessionHandle *data);
+
/* API setup for NSS */
#define curlssl_init Curl_nss_init
#define curlssl_cleanup Curl_nss_cleanup
diff --git a/lib/setup.h b/lib/setup.h
index 43f98a868..90bb898a3 100644
--- a/lib/setup.h
+++ b/lib/setup.h
@@ -530,7 +530,7 @@ int netware_init(void);
#endif
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_NTLM)
-#if defined(USE_SSLEAY) || defined(USE_WINDOWS_SSPI) || defined(USE_GNUTLS)
+#if defined(USE_SSLEAY) || defined(USE_WINDOWS_SSPI) || defined(USE_GNUTLS) || defined(USE_NSS)
#define USE_NTLM
#endif
#endif