diff options
| author | Max Khon <fjoe@samodelkin.net> | 2017-02-06 23:40:51 +0600 | 
|---|---|---|
| committer | Jay Satiro <raysatiro@yahoo.com> | 2017-02-20 00:53:01 -0500 | 
| commit | f77dabefd80b05173e602de94865b5cdffb3495e (patch) | |
| tree | a5c37a704433f7787765b0d4bb20ee76e20ed4b7 /lib | |
| parent | 889ca45ab896cc88b28bb9cc651f0bc1a8e54bc3 (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.h | 1 | ||||
| -rw-r--r-- | lib/vauth/digest_sspi.c | 243 | 
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 */  | 
