diff --git a/libsoup/soup-auth-ntlm.c b/libsoup/soup-auth-ntlm.c
--- a/libsoup/soup-auth-ntlm.c
+++ b/libsoup/soup-auth-ntlm.c
@@ -12,6 +12,8 @@
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
+#include <stdio.h>
+
 #include <glib.h>

 #include "soup-auth-ntlm.h"
@@ -26,14 +28,20 @@ static char       *soup_ntlm_request           (void);
 static gboolean    soup_ntlm_parse_challenge   (const char  *challenge,
 						char       **nonce,
 						char       **default_domain,
-						gboolean    *ntlmv2_session);
-static char       *soup_ntlm_response          (const char  *nonce,
+						gboolean    *ntlmv2_session,
+						gboolean    *negotiate_target,
+						char		**target_info,
+						size_t		*target_info_sz);
+static char       *soup_ntlm_response          (const char  *nonce,
 						const char  *user,
 						guchar       nt_hash[21],
 						guchar       lm_hash[21],
 						const char  *host,
 						const char  *domain,
-						gboolean     ntlmv2_session);
+						gboolean     ntlmv2_session,
+						gboolean     negotiate_target,
+						const char	*target_info,
+						size_t		target_info_sz);

 typedef enum {
 	SOUP_NTLM_NEW,
@@ -49,6 +57,9 @@ typedef struct {
 	char *nonce;
 	char *response_header;
 	gboolean ntlmv2_session;
+	gboolean negotiate_target;
+	char *target_info;
+	size_t target_info_sz;
 } SoupNTLMConnectionState;

 typedef enum {
@@ -339,7 +350,8 @@ soup_auth_ntlm_update_connection (SoupConnectionAuth *auth, SoupMessage *msg,

 	if (!soup_ntlm_parse_challenge (auth_header + 5, &conn->nonce,
 					priv->domain ? NULL : &priv->domain,
-					&conn->ntlmv2_session)) {
+					&conn->ntlmv2_session, &conn->negotiate_target,
+					&conn->target_info, &conn->target_info_sz)) {
 		conn->state = SOUP_NTLM_FAILED;
 		return FALSE;
 	}
@@ -521,7 +533,10 @@ soup_auth_ntlm_get_connection_authorization (SoupConnectionAuth *auth,
 						     priv->lm_hash,
 						     NULL,
 						     priv->domain,
-						     conn->ntlmv2_session);
+						     conn->ntlmv2_session,
+							 conn->negotiate_target,
+							 conn->target_info,
+							 conn->target_info_sz);
 		}
 		g_clear_pointer (&conn->nonce, g_free);
 		conn->state = SOUP_NTLM_SENT_RESPONSE;
@@ -647,9 +662,12 @@ typedef struct {
 #define NTLM_CHALLENGE_NONCE_OFFSET         24
 #define NTLM_CHALLENGE_NONCE_LENGTH          8
 #define NTLM_CHALLENGE_DOMAIN_STRING_OFFSET 12
+#define NTLM_TARGET_INFORMATION_OFFSET	40

 #define NTLM_CHALLENGE_FLAGS_OFFSET         20
 #define NTLM_FLAGS_NEGOTIATE_NTLMV2 0x00080000
+#define NTLM_FLAGS_NEGOTIATE_TARGET_INFORMATION 0x00800000
+#define NTLM_FLAGS_REQUEST_TARGET 0x00000004

 #define NTLM_RESPONSE_HEADER "NTLMSSP\x00\x03\x00\x00\x00"
 #define NTLM_RESPONSE_FLAGS 0x8201
@@ -686,10 +704,14 @@ static gboolean
 soup_ntlm_parse_challenge (const char *challenge,
 			   char      **nonce,
 			   char      **default_domain,
-			   gboolean   *ntlmv2_session)
+			   gboolean   *ntlmv2_session,
+			   gboolean   *negotiate_target,
+			   char		**target_info,
+			   size_t	*target_info_sz)
 {
 	gsize clen;
 	NTLMString domain;
+	NTLMString target;
 	guchar *chall;
 	guint32 flags;

@@ -703,6 +725,8 @@ soup_ntlm_parse_challenge (const char *challenge,
 	memcpy (&flags, chall + NTLM_CHALLENGE_FLAGS_OFFSET, sizeof(flags));
 	flags = GUINT_FROM_LE (flags);
 	*ntlmv2_session = (flags & NTLM_FLAGS_NEGOTIATE_NTLMV2) ? TRUE : FALSE;
+	/* To know if NTLMv2 responses should be calculated */
+	*negotiate_target = (flags & NTLM_FLAGS_NEGOTIATE_TARGET_INFORMATION ) ? TRUE : FALSE;

 	if (default_domain) {
 		memcpy (&domain, chall + NTLM_CHALLENGE_DOMAIN_STRING_OFFSET, sizeof (domain));
@@ -723,6 +747,19 @@ soup_ntlm_parse_challenge (const char *challenge,
 		*nonce = g_memdup (chall + NTLM_CHALLENGE_NONCE_OFFSET,
 				   NTLM_CHALLENGE_NONCE_LENGTH);
 	}
+	/* For NTLMv2 response */
+	if (*negotiate_target && target_info) {
+		memcpy (&target, chall + NTLM_TARGET_INFORMATION_OFFSET, sizeof (target));
+		target.length = GUINT16_FROM_LE (target.length);
+		target.offset = GUINT16_FROM_LE (target.offset);
+
+		if (clen < target.length + target.offset) {
+			g_free (chall);
+			return FALSE;
+		}
+		*target_info = g_memdup (chall + target.offset, target.length);
+		*target_info_sz = target.length;
+	}

 	g_free (chall);
 	return TRUE;
@@ -761,6 +798,92 @@ calc_ntlm2_session_response (const char *nonce,
 	calc_response (nt_hash, ntlmv2_hash, nt_resp);
 }

+/* Compute HMAC-MD5 with Glib function */
+static void
+calc_hmac_md5 (unsigned char *hmac, const guchar *key, gsize key_sz, const guchar *data, gsize data_sz)
+{
+	char *hmac_hex, *hex_pos;
+	size_t count;
+
+	hmac_hex = g_compute_hmac_for_data(G_CHECKSUM_MD5, key, key_sz, data, data_sz);
+	hex_pos = hmac_hex;
+	for (count = 0; count < 16; count++)
+	{
+		sscanf(hex_pos, "%2hhx", &hmac[count]);
+		hex_pos += 2;
+	}
+	g_free(hmac_hex);
+}
+
+static void
+calc_ntlmv2_response (const char *user, const char *domain,
+						const guchar *nt_hash, const guchar *nonce,
+						const char *target_info, size_t target_info_sz,
+						guchar *lm_resp, guchar *nt_resp)
+{
+	const unsigned char signature[] = {0x01,0x01,0x00,0x00};
+	const unsigned char reserved[] = {0x00,0x00,0x00,0x00};
+	const unsigned char unknown[] = {0x00,0x00,0x00,0x00};
+	unsigned char ntv2_hash[16], client_nonce[8], blob[28 + target_info_sz];
+	unsigned char nonce_blob[36 + target_info_sz], nonce_blob_hash[16];
+	unsigned char nonce_client_nonce[16], nonce_client_nonce_hash[16];
+	char *buf, *p, *user_domain;
+	unsigned char lmv2_resp[24], ntv2_resp[44 + target_info_sz];
+	gint64 timestamp;
+	size_t user_domain_sz;
+
+	/* create HMAC-MD5 hash of Unicode uppercase username and Unicode domain */
+	user_domain = g_strconcat (g_utf8_strup (user, sizeof(user)), domain, NULL);
+	user_domain_sz = strlen(user_domain);
+	p = buf = malloc (user_domain_sz * 2);
+	while (*user_domain)
+	{
+		*p++ = *user_domain++;
+		*p++ = '\0';
+	}
+	calc_hmac_md5 (ntv2_hash, (const guchar *)nt_hash, 16, (const guchar *)buf, user_domain_sz * 2);
+	free (buf);
+
+	/* create random client nonce */
+	for (int i = 0; i < 8; i++)
+	{
+		client_nonce[i] = g_random_int();
+	}
+
+	/* create timestamp for blob */
+	timestamp = GINT64_TO_LE(((unsigned long)time(NULL) + 11644473600) * 10000000);
+
+	/* create blob */
+	memset(blob, 0, target_info_sz + 28);
+	memcpy(blob, signature, 4);
+	memcpy(blob + 4, reserved, 4);
+	memcpy(blob + 8, &timestamp, 8);
+	memcpy(blob + 16, nonce, 8);
+	memcpy(blob + 24, unknown, 4);
+	memcpy(blob + 28, target_info, target_info_sz);
+
+	/* create HMAC-MD5 hash of concatenated nonce and blob */
+	memcpy(nonce_blob, nonce, 8);
+	memcpy(nonce_blob + 8, blob, sizeof(blob));
+	calc_hmac_md5 (nonce_blob_hash, ntv2_hash, 16, nonce_blob, 156);
+
+	/* create NTv2 response */
+	memcpy(ntv2_resp, nonce_blob_hash, 16);
+	memcpy(ntv2_resp + 16, blob, sizeof(blob));
+	memcpy(nt_resp, ntv2_resp, sizeof(ntv2_resp));
+
+	/* LMv2
+	 * create HMAC-MD5 hash of concatenated nonce and client nonce
+	 */
+	memcpy(nonce_client_nonce, nonce, 8);
+	memcpy(nonce_client_nonce + 8, client_nonce, 8);
+	calc_hmac_md5 (nonce_client_nonce_hash, ntv2_hash, 16, nonce_client_nonce, 16);
+
+	/* create LMv2 response */
+	memcpy(lmv2_resp, nonce_client_nonce_hash, 16);
+	memcpy(lmv2_resp + 16, client_nonce, 8);
+	memcpy(lm_resp, lmv2_resp, 24);
+}

 static char *
 soup_ntlm_response (const char *nonce,
@@ -769,31 +892,46 @@ soup_ntlm_response (const char *nonce,
 		    guchar      lm_hash[21],
 		    const char *host,
 		    const char *domain,
-		    gboolean    ntlmv2_session)
+		    gboolean    ntlmv2_session,
+			gboolean    negotiate_target,
+			const char	*target_info,
+			size_t		target_info_sz)
 {
 	int offset;
-	gsize hlen, dlen, ulen;
-	guchar lm_resp[24], nt_resp[24];
+	gsize hlen, dlen, ulen, nt_resp_sz;
+	guchar lm_resp[24], *nt_resp;
 	char *user_conv, *host_conv, *domain_conv;
 	NTLMResponse resp;
 	char *out, *p;
 	int state, save;

-	if (ntlmv2_session) {
+	if (negotiate_target)
+	{
+		nt_resp = g_malloc(44 + target_info_sz);
+		nt_resp_sz = 44 + target_info_sz;
+	} else {
+		nt_resp = g_malloc(24);
+		nt_resp_sz = 24;
+	}
+
+	if (ntlmv2_session && !negotiate_target) {
 		calc_ntlm2_session_response (nonce, nt_hash, lm_hash,
 					     lm_resp, sizeof(lm_resp), nt_resp);
-	} else {
-		/* Compute a regular response */
+	} else if (!negotiate_target){
+		/* Compute a regular NTLMv1 response */
 		calc_response (nt_hash, (guchar *) nonce, nt_resp);
 		calc_response (lm_hash, (guchar *) nonce, lm_resp);
+	} else {
+		calc_ntlmv2_response (user, domain, nt_hash, (guchar *) nonce, target_info, target_info_sz, lm_resp, nt_resp);
 	}

 	memset (&resp, 0, sizeof (resp));
 	memcpy (resp.header, NTLM_RESPONSE_HEADER, sizeof (resp.header));
 	resp.flags = GUINT32_TO_LE (NTLM_RESPONSE_FLAGS);
-	if (ntlmv2_session)
+	if (ntlmv2_session && !negotiate_target)
 		resp.flags |= GUINT32_TO_LE (NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY);
-
+	if (negotiate_target)
+			resp.flags |= GUINT32_TO_LE (NTLM_FLAGS_REQUEST_TARGET);
 	offset = sizeof (resp);

 	if (!host)
@@ -807,7 +945,7 @@ soup_ntlm_response (const char *nonce,
 	ntlm_set_string (&resp.user, &offset, ulen);
 	ntlm_set_string (&resp.host, &offset, hlen);
 	ntlm_set_string (&resp.lm_resp, &offset, sizeof (lm_resp));
-	ntlm_set_string (&resp.nt_resp, &offset, sizeof (nt_resp));
+	ntlm_set_string (&resp.nt_resp, &offset, nt_resp_sz);

 	out = g_malloc (((offset + 3) * 4) / 3 + 6);
 	strncpy (out, "NTLM ", 5);
@@ -825,7 +963,7 @@ soup_ntlm_response (const char *nonce,
 				   FALSE, p, &state, &save);
 	p += g_base64_encode_step (lm_resp, sizeof (lm_resp),
 				   FALSE, p, &state, &save);
-	p += g_base64_encode_step (nt_resp, sizeof (nt_resp),
+	p += g_base64_encode_step (nt_resp, nt_resp_sz,
 				   FALSE, p, &state, &save);
 	p += g_base64_encode_close (FALSE, p, &state, &save);
 	*p = '\0';
@@ -833,6 +971,7 @@ soup_ntlm_response (const char *nonce,
 	g_free (domain_conv);
 	g_free (user_conv);
 	g_free (host_conv);
+	g_free (nt_resp);

 	return out;
 }
