aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMax Khon <fjoe@samodelkin.net>2017-02-06 23:40:51 +0600
committerJay Satiro <raysatiro@yahoo.com>2017-02-20 00:53:01 -0500
commitf77dabefd80b05173e602de94865b5cdffb3495e (patch)
treea5c37a704433f7787765b0d4bb20ee76e20ed4b7 /lib
parent889ca45ab896cc88b28bb9cc651f0bc1a8e54bc3 (diff)
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
Diffstat (limited to 'lib')
-rw-r--r--lib/urldata.h1
-rw-r--r--lib/vauth/digest_sspi.c243
2 files changed, 145 insertions, 99 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 */