gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] [gnurl] 147/173: digest_sspi: Fix nonce-count generation in


From: gnunet
Subject: [GNUnet-SVN] [gnurl] 147/173: digest_sspi: Fix nonce-count generation in HTTP digest
Date: Fri, 24 Feb 2017 14:02:49 +0100

This is an automated email from the git hooks/post-receive script.

ng0 pushed a commit to annotated tag gnurl-7.53.1
in repository gnurl.

commit f77dabefd80b05173e602de94865b5cdffb3495e
Author: Max Khon <address@hidden>
AuthorDate: Mon Feb 6 23:40:51 2017 +0600

    digest_sspi: Fix nonce-count generation in HTTP digest
    
    - on the first invocation: keep security context returned by
      InitializeSecurityContext()
    
    - on subsequent invocations: use MakeSignature() instead of
      InitializeSecurityContext() to generate HTTP digest response
    
    Bug: https://github.com/curl/curl/issues/870
    Reported-by: Andreas Roth
    
    Closes https://github.com/curl/curl/pull/1251
---
 lib/urldata.h           |   1 +
 lib/vauth/digest_sspi.c | 243 ++++++++++++++++++++++++++++--------------------
 tests/data/Makefile.inc |   2 +-
 tests/data/test1286     | 110 ++++++++++++++++++++++
 4 files changed, 256 insertions(+), 100 deletions(-)

diff --git a/lib/urldata.h b/lib/urldata.h
index c17e42cc0..648b3e81d 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -408,6 +408,7 @@ struct digestdata {
 #if defined(USE_WINDOWS_SSPI)
   BYTE *input_token;
   size_t input_token_len;
+  CtxtHandle *http_context;
 #else
   char *nonce;
   char *cnonce;
diff --git a/lib/vauth/digest_sspi.c b/lib/vauth/digest_sspi.c
index 6f0746fc4..f9ee8a8fd 100644
--- a/lib/vauth/digest_sspi.c
+++ b/lib/vauth/digest_sspi.c
@@ -379,21 +379,13 @@ CURLcode Curl_auth_create_digest_http_message(struct 
Curl_easy *data,
                                               char **outptr, size_t *outlen)
 {
   size_t token_max;
-  CredHandle credentials;
-  CtxtHandle context;
   char *resp;
   BYTE *output_token;
+  size_t output_token_len;
   PSecPkgInfo SecurityPackage;
-  SEC_WINNT_AUTH_IDENTITY identity;
-  SEC_WINNT_AUTH_IDENTITY *p_identity;
-  SecBuffer chlg_buf[3];
-  SecBuffer resp_buf;
+  SecBuffer chlg_buf[5];
   SecBufferDesc chlg_desc;
-  SecBufferDesc resp_desc;
   SECURITY_STATUS status;
-  unsigned long attrs;
-  TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
-  TCHAR *spn;
 
   (void) data;
 
@@ -408,123 +400,170 @@ CURLcode Curl_auth_create_digest_http_message(struct 
Curl_easy *data,
   /* Release the package buffer as it is not required anymore */
   s_pSecFn->FreeContextBuffer(SecurityPackage);
 
-  if(userp && *userp) {
-    /* Populate our identity structure */
-    if(Curl_create_sspi_identity(userp, passwdp, &identity))
-      return CURLE_OUT_OF_MEMORY;
-
-    /* Populate our identity domain */
-    if(Curl_override_sspi_http_realm((const char *) digest->input_token,
-                                     &identity))
-      return CURLE_OUT_OF_MEMORY;
+  /* Allocate the output buffer according to the max token size as indicated
+     by the security package */
+  output_token = malloc(token_max);
+  if(!output_token) {
+    return CURLE_OUT_OF_MEMORY;
+  }
 
-    /* Allow proper cleanup of the identity structure */
-    p_identity = &identity;
+  if(digest->http_context) {
+    chlg_desc.ulVersion    = SECBUFFER_VERSION;
+    chlg_desc.cBuffers     = 5;
+    chlg_desc.pBuffers     = chlg_buf;
+    chlg_buf[0].BufferType = SECBUFFER_TOKEN;
+    chlg_buf[0].pvBuffer   = NULL;
+    chlg_buf[0].cbBuffer   = 0;
+    chlg_buf[1].BufferType = SECBUFFER_PKG_PARAMS;
+    chlg_buf[1].pvBuffer   = (void *) request;
+    chlg_buf[1].cbBuffer   = curlx_uztoul(strlen((const char *) request));
+    chlg_buf[2].BufferType = SECBUFFER_PKG_PARAMS;
+    chlg_buf[2].pvBuffer   = (void *) uripath;
+    chlg_buf[2].cbBuffer   = curlx_uztoul(strlen((const char *) uripath));
+    chlg_buf[3].BufferType = SECBUFFER_PKG_PARAMS;
+    chlg_buf[3].pvBuffer   = NULL;
+    chlg_buf[3].cbBuffer   = 0;
+    chlg_buf[4].BufferType = SECBUFFER_PADDING;
+    chlg_buf[4].pvBuffer   = output_token;
+    chlg_buf[4].cbBuffer   = curlx_uztoul(token_max);
+
+    status = s_pSecFn->MakeSignature(digest->http_context, 0, &chlg_desc, 0);
+    if(status == SEC_E_OK)
+      output_token_len = chlg_buf[4].cbBuffer;
+    else { /* delete the context so a new one can be made */
+      infof(data, "digest_sspi: MakeSignature failed, error 0x%08lx\n",
+            (long)status);
+      s_pSecFn->DeleteSecurityContext(digest->http_context);
+      Curl_safefree(digest->http_context);
+    }
   }
-  else
-    /* Use the current Windows user */
-    p_identity = NULL;
 
-  /* Acquire our credentials handle */
-  status = s_pSecFn->AcquireCredentialsHandle(NULL,
-                                              (TCHAR *) TEXT(SP_NAME_DIGEST),
-                                              SECPKG_CRED_OUTBOUND, NULL,
-                                              p_identity, NULL, NULL,
-                                              &credentials, &expiry);
-  if(status != SEC_E_OK) {
-    Curl_sspi_free_identity(p_identity);
+  if(!digest->http_context) {
+    CredHandle credentials;
+    SEC_WINNT_AUTH_IDENTITY identity;
+    SEC_WINNT_AUTH_IDENTITY *p_identity;
+    SecBuffer resp_buf;
+    SecBufferDesc resp_desc;
+    unsigned long attrs;
+    TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
+    TCHAR *spn;
+
+    if(userp && *userp) {
+      /* Populate our identity structure */
+      if(Curl_create_sspi_identity(userp, passwdp, &identity)) {
+        free(output_token);
+        return CURLE_OUT_OF_MEMORY;
+      }
 
-    return CURLE_LOGIN_DENIED;
-  }
+      /* Populate our identity domain */
+      if(Curl_override_sspi_http_realm((const char *) digest->input_token,
+                                       &identity)) {
+        free(output_token);
+        return CURLE_OUT_OF_MEMORY;
+      }
 
-  /* Allocate the output buffer according to the max token size as indicated
-     by the security package */
-  output_token = malloc(token_max);
-  if(!output_token) {
-    s_pSecFn->FreeCredentialsHandle(&credentials);
+      /* Allow proper cleanup of the identity structure */
+      p_identity = &identity;
+    }
+    else
+      /* Use the current Windows user */
+      p_identity = NULL;
+
+    /* Acquire our credentials handle */
+    status = s_pSecFn->AcquireCredentialsHandle(NULL,
+                                                (TCHAR *) TEXT(SP_NAME_DIGEST),
+                                                SECPKG_CRED_OUTBOUND, NULL,
+                                                p_identity, NULL, NULL,
+                                                &credentials, &expiry);
+    if(status != SEC_E_OK) {
+      Curl_sspi_free_identity(p_identity);
+      free(output_token);
 
-    Curl_sspi_free_identity(p_identity);
+      return CURLE_LOGIN_DENIED;
+    }
 
-    return CURLE_OUT_OF_MEMORY;
-  }
+    /* Setup the challenge "input" security buffer if present */
+    chlg_desc.ulVersion    = SECBUFFER_VERSION;
+    chlg_desc.cBuffers     = 3;
+    chlg_desc.pBuffers     = chlg_buf;
+    chlg_buf[0].BufferType = SECBUFFER_TOKEN;
+    chlg_buf[0].pvBuffer   = digest->input_token;
+    chlg_buf[0].cbBuffer   = curlx_uztoul(digest->input_token_len);
+    chlg_buf[1].BufferType = SECBUFFER_PKG_PARAMS;
+    chlg_buf[1].pvBuffer   = (void *) request;
+    chlg_buf[1].cbBuffer   = curlx_uztoul(strlen((const char *) request));
+    chlg_buf[2].BufferType = SECBUFFER_PKG_PARAMS;
+    chlg_buf[2].pvBuffer   = NULL;
+    chlg_buf[2].cbBuffer   = 0;
+
+    /* Setup the response "output" security buffer */
+    resp_desc.ulVersion = SECBUFFER_VERSION;
+    resp_desc.cBuffers  = 1;
+    resp_desc.pBuffers  = &resp_buf;
+    resp_buf.BufferType = SECBUFFER_TOKEN;
+    resp_buf.pvBuffer   = output_token;
+    resp_buf.cbBuffer   = curlx_uztoul(token_max);
+
+    spn = Curl_convert_UTF8_to_tchar((char *) uripath);
+    if(!spn) {
+      s_pSecFn->FreeCredentialsHandle(&credentials);
+
+      Curl_sspi_free_identity(p_identity);
+      free(output_token);
 
-  /* Setup the challenge "input" security buffer if present */
-  chlg_desc.ulVersion    = SECBUFFER_VERSION;
-  chlg_desc.cBuffers     = 3;
-  chlg_desc.pBuffers     = chlg_buf;
-  chlg_buf[0].BufferType = SECBUFFER_TOKEN;
-  chlg_buf[0].pvBuffer   = digest->input_token;
-  chlg_buf[0].cbBuffer   = curlx_uztoul(digest->input_token_len);
-  chlg_buf[1].BufferType = SECBUFFER_PKG_PARAMS;
-  chlg_buf[1].pvBuffer   = (void *) request;
-  chlg_buf[1].cbBuffer   = curlx_uztoul(strlen((const char *) request));
-  chlg_buf[2].BufferType = SECBUFFER_PKG_PARAMS;
-  chlg_buf[2].pvBuffer   = NULL;
-  chlg_buf[2].cbBuffer   = 0;
+      return CURLE_OUT_OF_MEMORY;
+    }
 
-  /* Setup the response "output" security buffer */
-  resp_desc.ulVersion = SECBUFFER_VERSION;
-  resp_desc.cBuffers  = 1;
-  resp_desc.pBuffers  = &resp_buf;
-  resp_buf.BufferType = SECBUFFER_TOKEN;
-  resp_buf.pvBuffer   = output_token;
-  resp_buf.cbBuffer   = curlx_uztoul(token_max);
+    /* Allocate our new context handle */
+    digest->http_context = calloc(1, sizeof(CtxtHandle));
+    if(!digest->http_context)
+      return CURLE_OUT_OF_MEMORY;
 
-  spn = Curl_convert_UTF8_to_tchar((char *) uripath);
-  if(!spn) {
-    s_pSecFn->FreeCredentialsHandle(&credentials);
+    /* Generate our reponse message */
+    status = s_pSecFn->InitializeSecurityContext(&credentials, NULL,
+                                                 spn,
+                                                 ISC_REQ_USE_HTTP_STYLE, 0, 0,
+                                                 &chlg_desc, 0,
+                                                 digest->http_context,
+                                                 &resp_desc, &attrs, &expiry);
+    Curl_unicodefree(spn);
+
+    if(status == SEC_I_COMPLETE_NEEDED ||
+       status == SEC_I_COMPLETE_AND_CONTINUE)
+      s_pSecFn->CompleteAuthToken(&credentials, &resp_desc);
+    else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
+      s_pSecFn->FreeCredentialsHandle(&credentials);
+
+      Curl_sspi_free_identity(p_identity);
+      free(output_token);
 
-    Curl_sspi_free_identity(p_identity);
-    free(output_token);
+      Curl_safefree(digest->http_context);
 
-    return CURLE_OUT_OF_MEMORY;
-  }
+      return CURLE_OUT_OF_MEMORY;
+    }
 
-  /* Generate our reponse message */
-  status = s_pSecFn->InitializeSecurityContext(&credentials, NULL,
-                                               spn,
-                                               ISC_REQ_USE_HTTP_STYLE, 0, 0,
-                                               &chlg_desc, 0, &context,
-                                               &resp_desc, &attrs, &expiry);
-  Curl_unicodefree(spn);
+    output_token_len = resp_buf.cbBuffer;
 
-  if(status == SEC_I_COMPLETE_NEEDED ||
-     status == SEC_I_COMPLETE_AND_CONTINUE)
-    s_pSecFn->CompleteAuthToken(&credentials, &resp_desc);
-  else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
     s_pSecFn->FreeCredentialsHandle(&credentials);
-
     Curl_sspi_free_identity(p_identity);
-    free(output_token);
-
-    return CURLE_OUT_OF_MEMORY;
   }
 
-  resp = malloc(resp_buf.cbBuffer + 1);
+  resp = malloc(output_token_len + 1);
   if(!resp) {
-    s_pSecFn->DeleteSecurityContext(&context);
-    s_pSecFn->FreeCredentialsHandle(&credentials);
-
-    Curl_sspi_free_identity(p_identity);
     free(output_token);
 
+    Curl_safefree(digest->http_context);
+
     return CURLE_OUT_OF_MEMORY;
   }
 
   /* Copy the generated reponse */
-  memcpy(resp, resp_buf.pvBuffer, resp_buf.cbBuffer);
-  resp[resp_buf.cbBuffer] = 0x00;
+  memcpy(resp, output_token, output_token_len);
+  resp[output_token_len] = 0;
 
   /* Return the response */
   *outptr = resp;
-  *outlen = resp_buf.cbBuffer;
-
-  /* Free our handles */
-  s_pSecFn->DeleteSecurityContext(&context);
-  s_pSecFn->FreeCredentialsHandle(&credentials);
-
-  /* Free the identity structure */
-  Curl_sspi_free_identity(p_identity);
+  *outlen = output_token_len;
 
   /* Free the response buffer */
   free(output_token);
@@ -549,6 +588,12 @@ void Curl_auth_digest_cleanup(struct digestdata *digest)
 
   /* Reset any variables */
   digest->input_token_len = 0;
+
+  /* Delete security context */
+  if(digest->http_context) {
+    s_pSecFn->DeleteSecurityContext(digest->http_context);
+    Curl_safefree(digest->http_context);
+  }
 }
 
 #endif /* USE_WINDOWS_SSPI && !CURL_DISABLE_CRYPTO_AUTH */
diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc
index 33dce05d8..8251ab9a4 100644
--- a/tests/data/Makefile.inc
+++ b/tests/data/Makefile.inc
@@ -130,7 +130,7 @@ test1236 test1237 test1238 test1239 test1240 test1241 
test1242 test1243 \
 test1244 test1245 test1246 test1247 test1248 test1249 test1250 test1251 \
 test1252 test1253 test1254 test1255 test1256 test1257 test1258 test1259 \
 \
-test1280 test1281 test1282 test1283 test1284 test1285 \
+test1280 test1281 test1282 test1283 test1284 test1285 test1286 \
 \
 test1300 test1301 test1302 test1303 test1304 test1305 test1306 test1307 \
 test1308 test1309 test1310 test1311 test1312 test1313 test1314 test1315 \
diff --git a/tests/data/test1286 b/tests/data/test1286
new file mode 100644
index 000000000..41782cb0f
--- /dev/null
+++ b/tests/data/test1286
@@ -0,0 +1,110 @@
+<testcase>
+<info>
+<keywords>
+HTTP
+HTTP GET
+HTTP Digest auth
+followlocation
+</keywords>
+</info>
+
+# Server-side
+<reply>
+<data>
+HTTP/1.1 401 authentication please swsbounce
+Server: Microsoft-IIS/6.0
+WWW-Authenticate: Digest realm="testrealm", nonce="1053604144", qop="auth"
+Content-Type: text/html; charset=iso-8859-1
+Content-Length: 0
+
+</data>
+<data1000>
+HTTP/1.1 302 Thanks for this, but we want to redir you!
+Server: Microsoft-IIS/5.0
+Content-Type: text/html; charset=iso-8859-1
+Location: /12860001
+Content-Length: 0
+
+</data1000>
+<data1001>
+HTTP/1.1 404 Not Found
+Server: Microsoft-IIS/5.0
+Content-Type: text/html; charset=iso-8859-1
+Content-Length: 0
+
+</data1001>
+
+<datacheck>
+HTTP/1.1 401 authentication please swsbounce
+Server: Microsoft-IIS/6.0
+WWW-Authenticate: Digest realm="testrealm", nonce="1053604144", qop="auth"
+Content-Type: text/html; charset=iso-8859-1
+Content-Length: 0
+
+HTTP/1.1 302 Thanks for this, but we want to redir you!
+Server: Microsoft-IIS/5.0
+Content-Type: text/html; charset=iso-8859-1
+Location: /12860001
+Content-Length: 0
+
+HTTP/1.1 404 Not Found
+Server: Microsoft-IIS/5.0
+Content-Type: text/html; charset=iso-8859-1
+Content-Length: 0
+
+</datacheck>
+
+</reply>
+
+# Client-side
+<client>
+#
+<server>
+http
+</server>
+<features>
+crypto
+</features>
+<name>
+HTTP GET --digest increasing nonce-count
+</name>
+# This test is to ensure the nonce-count (nc) increases
+# https://github.com/curl/curl/pull/1251
+<command>
+-u auser:apasswd --location --digest http://%HOSTIP:%HTTPPORT/1286
+</command>
+</client>
+
+# Verify data after the test has been "shot"
+<verify>
+<strip>
+^User-Agent:.*
+</strip>
+# Reorder the fields in 'Authorization: Digest' header.
+# Since regular and SSPI digest auth header fields may not have the same order
+# or whitespace we homogenize so that both may be tested. Also:
+# - Remove the unique value from cnonce if in RFC format
+# - Remove the unique value from response if in RFC format
+# - Remove quotes from qop="auth" used by SSPI
+# The if statement is one line because runtests evaluates one line at a time.
+<strippart>
+if(s/^(Authorization: Digest )([^\r\n]+)(\r?\n)$//) { $_ = $1 . join(', ', map 
{ s/^(cnonce=)"[a-zA-Z0-9+\/=]+"$/$1REMOVED/; 
s/^(response=)"[a-f0-9]{32}"$/$1REMOVED/; s/^qop="auth"$/qop=auth/; $_ } sort 
split(/, */, $2)) . $3; }
+</strippart>
+<protocol>
+GET /1286 HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+Accept: */*
+
+GET /1286 HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+Authorization: Digest cnonce=REMOVED, nc=00000001, nonce="1053604144", 
qop=auth, realm="testrealm", response=REMOVED, uri="/1286", username="auser"
+Accept: */*
+
+GET /12860001 HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+Authorization: Digest cnonce=REMOVED, nc=00000002, nonce="1053604144", 
qop=auth, realm="testrealm", response=REMOVED, uri="/12860001", username="auser"
+Accept: */*
+
+</protocol>
+</verify>
+</testcase>

-- 
To stop receiving notification emails like this one, please contact
address@hidden



reply via email to

[Prev in Thread] Current Thread [Next in Thread]