113498266Sopenharmony_ci/*************************************************************************** 213498266Sopenharmony_ci * _ _ ____ _ 313498266Sopenharmony_ci * Project ___| | | | _ \| | 413498266Sopenharmony_ci * / __| | | | |_) | | 513498266Sopenharmony_ci * | (__| |_| | _ <| |___ 613498266Sopenharmony_ci * \___|\___/|_| \_\_____| 713498266Sopenharmony_ci * 813498266Sopenharmony_ci * Copyright (C) Steve Holme, <steve_holme@hotmail.com>. 913498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 1013498266Sopenharmony_ci * 1113498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which 1213498266Sopenharmony_ci * you should have received as part of this distribution. The terms 1313498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html. 1413498266Sopenharmony_ci * 1513498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell 1613498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is 1713498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file. 1813498266Sopenharmony_ci * 1913498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 2013498266Sopenharmony_ci * KIND, either express or implied. 2113498266Sopenharmony_ci * 2213498266Sopenharmony_ci * SPDX-License-Identifier: curl 2313498266Sopenharmony_ci * 2413498266Sopenharmony_ci * RFC2831 DIGEST-MD5 authentication 2513498266Sopenharmony_ci * 2613498266Sopenharmony_ci ***************************************************************************/ 2713498266Sopenharmony_ci 2813498266Sopenharmony_ci#include "curl_setup.h" 2913498266Sopenharmony_ci 3013498266Sopenharmony_ci#if defined(USE_WINDOWS_SSPI) && !defined(CURL_DISABLE_DIGEST_AUTH) 3113498266Sopenharmony_ci 3213498266Sopenharmony_ci#include <curl/curl.h> 3313498266Sopenharmony_ci 3413498266Sopenharmony_ci#include "vauth/vauth.h" 3513498266Sopenharmony_ci#include "vauth/digest.h" 3613498266Sopenharmony_ci#include "urldata.h" 3713498266Sopenharmony_ci#include "warnless.h" 3813498266Sopenharmony_ci#include "curl_multibyte.h" 3913498266Sopenharmony_ci#include "sendf.h" 4013498266Sopenharmony_ci#include "strdup.h" 4113498266Sopenharmony_ci#include "strcase.h" 4213498266Sopenharmony_ci#include "strerror.h" 4313498266Sopenharmony_ci 4413498266Sopenharmony_ci/* The last #include files should be: */ 4513498266Sopenharmony_ci#include "curl_memory.h" 4613498266Sopenharmony_ci#include "memdebug.h" 4713498266Sopenharmony_ci 4813498266Sopenharmony_ci/* 4913498266Sopenharmony_ci* Curl_auth_is_digest_supported() 5013498266Sopenharmony_ci* 5113498266Sopenharmony_ci* This is used to evaluate if DIGEST is supported. 5213498266Sopenharmony_ci* 5313498266Sopenharmony_ci* Parameters: None 5413498266Sopenharmony_ci* 5513498266Sopenharmony_ci* Returns TRUE if DIGEST is supported by Windows SSPI. 5613498266Sopenharmony_ci*/ 5713498266Sopenharmony_cibool Curl_auth_is_digest_supported(void) 5813498266Sopenharmony_ci{ 5913498266Sopenharmony_ci PSecPkgInfo SecurityPackage; 6013498266Sopenharmony_ci SECURITY_STATUS status; 6113498266Sopenharmony_ci 6213498266Sopenharmony_ci /* Query the security package for Digest */ 6313498266Sopenharmony_ci status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST), 6413498266Sopenharmony_ci &SecurityPackage); 6513498266Sopenharmony_ci 6613498266Sopenharmony_ci /* Release the package buffer as it is not required anymore */ 6713498266Sopenharmony_ci if(status == SEC_E_OK) { 6813498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(SecurityPackage); 6913498266Sopenharmony_ci } 7013498266Sopenharmony_ci 7113498266Sopenharmony_ci return (status == SEC_E_OK ? TRUE : FALSE); 7213498266Sopenharmony_ci} 7313498266Sopenharmony_ci 7413498266Sopenharmony_ci/* 7513498266Sopenharmony_ci * Curl_auth_create_digest_md5_message() 7613498266Sopenharmony_ci * 7713498266Sopenharmony_ci * This is used to generate an already encoded DIGEST-MD5 response message 7813498266Sopenharmony_ci * ready for sending to the recipient. 7913498266Sopenharmony_ci * 8013498266Sopenharmony_ci * Parameters: 8113498266Sopenharmony_ci * 8213498266Sopenharmony_ci * data [in] - The session handle. 8313498266Sopenharmony_ci * chlg [in] - The challenge message. 8413498266Sopenharmony_ci * userp [in] - The user name in the format User or Domain\User. 8513498266Sopenharmony_ci * passwdp [in] - The user's password. 8613498266Sopenharmony_ci * service [in] - The service type such as http, smtp, pop or imap. 8713498266Sopenharmony_ci * out [out] - The result storage. 8813498266Sopenharmony_ci * 8913498266Sopenharmony_ci * Returns CURLE_OK on success. 9013498266Sopenharmony_ci */ 9113498266Sopenharmony_ciCURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, 9213498266Sopenharmony_ci const struct bufref *chlg, 9313498266Sopenharmony_ci const char *userp, 9413498266Sopenharmony_ci const char *passwdp, 9513498266Sopenharmony_ci const char *service, 9613498266Sopenharmony_ci struct bufref *out) 9713498266Sopenharmony_ci{ 9813498266Sopenharmony_ci CURLcode result = CURLE_OK; 9913498266Sopenharmony_ci TCHAR *spn = NULL; 10013498266Sopenharmony_ci size_t token_max = 0; 10113498266Sopenharmony_ci unsigned char *output_token = NULL; 10213498266Sopenharmony_ci CredHandle credentials; 10313498266Sopenharmony_ci CtxtHandle context; 10413498266Sopenharmony_ci PSecPkgInfo SecurityPackage; 10513498266Sopenharmony_ci SEC_WINNT_AUTH_IDENTITY identity; 10613498266Sopenharmony_ci SEC_WINNT_AUTH_IDENTITY *p_identity; 10713498266Sopenharmony_ci SecBuffer chlg_buf; 10813498266Sopenharmony_ci SecBuffer resp_buf; 10913498266Sopenharmony_ci SecBufferDesc chlg_desc; 11013498266Sopenharmony_ci SecBufferDesc resp_desc; 11113498266Sopenharmony_ci SECURITY_STATUS status; 11213498266Sopenharmony_ci unsigned long attrs; 11313498266Sopenharmony_ci TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ 11413498266Sopenharmony_ci 11513498266Sopenharmony_ci /* Ensure we have a valid challenge message */ 11613498266Sopenharmony_ci if(!Curl_bufref_len(chlg)) { 11713498266Sopenharmony_ci infof(data, "DIGEST-MD5 handshake failure (empty challenge message)"); 11813498266Sopenharmony_ci return CURLE_BAD_CONTENT_ENCODING; 11913498266Sopenharmony_ci } 12013498266Sopenharmony_ci 12113498266Sopenharmony_ci /* Query the security package for DigestSSP */ 12213498266Sopenharmony_ci status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST), 12313498266Sopenharmony_ci &SecurityPackage); 12413498266Sopenharmony_ci if(status != SEC_E_OK) { 12513498266Sopenharmony_ci failf(data, "SSPI: couldn't get auth info"); 12613498266Sopenharmony_ci return CURLE_AUTH_ERROR; 12713498266Sopenharmony_ci } 12813498266Sopenharmony_ci 12913498266Sopenharmony_ci token_max = SecurityPackage->cbMaxToken; 13013498266Sopenharmony_ci 13113498266Sopenharmony_ci /* Release the package buffer as it is not required anymore */ 13213498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(SecurityPackage); 13313498266Sopenharmony_ci 13413498266Sopenharmony_ci /* Allocate our response buffer */ 13513498266Sopenharmony_ci output_token = malloc(token_max); 13613498266Sopenharmony_ci if(!output_token) 13713498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 13813498266Sopenharmony_ci 13913498266Sopenharmony_ci /* Generate our SPN */ 14013498266Sopenharmony_ci spn = Curl_auth_build_spn(service, data->conn->host.name, NULL); 14113498266Sopenharmony_ci if(!spn) { 14213498266Sopenharmony_ci free(output_token); 14313498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 14413498266Sopenharmony_ci } 14513498266Sopenharmony_ci 14613498266Sopenharmony_ci if(userp && *userp) { 14713498266Sopenharmony_ci /* Populate our identity structure */ 14813498266Sopenharmony_ci result = Curl_create_sspi_identity(userp, passwdp, &identity); 14913498266Sopenharmony_ci if(result) { 15013498266Sopenharmony_ci free(spn); 15113498266Sopenharmony_ci free(output_token); 15213498266Sopenharmony_ci return result; 15313498266Sopenharmony_ci } 15413498266Sopenharmony_ci 15513498266Sopenharmony_ci /* Allow proper cleanup of the identity structure */ 15613498266Sopenharmony_ci p_identity = &identity; 15713498266Sopenharmony_ci } 15813498266Sopenharmony_ci else 15913498266Sopenharmony_ci /* Use the current Windows user */ 16013498266Sopenharmony_ci p_identity = NULL; 16113498266Sopenharmony_ci 16213498266Sopenharmony_ci /* Acquire our credentials handle */ 16313498266Sopenharmony_ci status = s_pSecFn->AcquireCredentialsHandle(NULL, 16413498266Sopenharmony_ci (TCHAR *) TEXT(SP_NAME_DIGEST), 16513498266Sopenharmony_ci SECPKG_CRED_OUTBOUND, NULL, 16613498266Sopenharmony_ci p_identity, NULL, NULL, 16713498266Sopenharmony_ci &credentials, &expiry); 16813498266Sopenharmony_ci 16913498266Sopenharmony_ci if(status != SEC_E_OK) { 17013498266Sopenharmony_ci Curl_sspi_free_identity(p_identity); 17113498266Sopenharmony_ci free(spn); 17213498266Sopenharmony_ci free(output_token); 17313498266Sopenharmony_ci return CURLE_LOGIN_DENIED; 17413498266Sopenharmony_ci } 17513498266Sopenharmony_ci 17613498266Sopenharmony_ci /* Setup the challenge "input" security buffer */ 17713498266Sopenharmony_ci chlg_desc.ulVersion = SECBUFFER_VERSION; 17813498266Sopenharmony_ci chlg_desc.cBuffers = 1; 17913498266Sopenharmony_ci chlg_desc.pBuffers = &chlg_buf; 18013498266Sopenharmony_ci chlg_buf.BufferType = SECBUFFER_TOKEN; 18113498266Sopenharmony_ci chlg_buf.pvBuffer = (void *) Curl_bufref_ptr(chlg); 18213498266Sopenharmony_ci chlg_buf.cbBuffer = curlx_uztoul(Curl_bufref_len(chlg)); 18313498266Sopenharmony_ci 18413498266Sopenharmony_ci /* Setup the response "output" security buffer */ 18513498266Sopenharmony_ci resp_desc.ulVersion = SECBUFFER_VERSION; 18613498266Sopenharmony_ci resp_desc.cBuffers = 1; 18713498266Sopenharmony_ci resp_desc.pBuffers = &resp_buf; 18813498266Sopenharmony_ci resp_buf.BufferType = SECBUFFER_TOKEN; 18913498266Sopenharmony_ci resp_buf.pvBuffer = output_token; 19013498266Sopenharmony_ci resp_buf.cbBuffer = curlx_uztoul(token_max); 19113498266Sopenharmony_ci 19213498266Sopenharmony_ci /* Generate our response message */ 19313498266Sopenharmony_ci status = s_pSecFn->InitializeSecurityContext(&credentials, NULL, spn, 19413498266Sopenharmony_ci 0, 0, 0, &chlg_desc, 0, 19513498266Sopenharmony_ci &context, &resp_desc, &attrs, 19613498266Sopenharmony_ci &expiry); 19713498266Sopenharmony_ci 19813498266Sopenharmony_ci if(status == SEC_I_COMPLETE_NEEDED || 19913498266Sopenharmony_ci status == SEC_I_COMPLETE_AND_CONTINUE) 20013498266Sopenharmony_ci s_pSecFn->CompleteAuthToken(&credentials, &resp_desc); 20113498266Sopenharmony_ci else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { 20213498266Sopenharmony_ci#if !defined(CURL_DISABLE_VERBOSE_STRINGS) 20313498266Sopenharmony_ci char buffer[STRERROR_LEN]; 20413498266Sopenharmony_ci#endif 20513498266Sopenharmony_ci 20613498266Sopenharmony_ci s_pSecFn->FreeCredentialsHandle(&credentials); 20713498266Sopenharmony_ci Curl_sspi_free_identity(p_identity); 20813498266Sopenharmony_ci free(spn); 20913498266Sopenharmony_ci free(output_token); 21013498266Sopenharmony_ci 21113498266Sopenharmony_ci if(status == SEC_E_INSUFFICIENT_MEMORY) 21213498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 21313498266Sopenharmony_ci 21413498266Sopenharmony_ci#if !defined(CURL_DISABLE_VERBOSE_STRINGS) 21513498266Sopenharmony_ci infof(data, "schannel: InitializeSecurityContext failed: %s", 21613498266Sopenharmony_ci Curl_sspi_strerror(status, buffer, sizeof(buffer))); 21713498266Sopenharmony_ci#endif 21813498266Sopenharmony_ci 21913498266Sopenharmony_ci return CURLE_AUTH_ERROR; 22013498266Sopenharmony_ci } 22113498266Sopenharmony_ci 22213498266Sopenharmony_ci /* Return the response. */ 22313498266Sopenharmony_ci Curl_bufref_set(out, output_token, resp_buf.cbBuffer, curl_free); 22413498266Sopenharmony_ci 22513498266Sopenharmony_ci /* Free our handles */ 22613498266Sopenharmony_ci s_pSecFn->DeleteSecurityContext(&context); 22713498266Sopenharmony_ci s_pSecFn->FreeCredentialsHandle(&credentials); 22813498266Sopenharmony_ci 22913498266Sopenharmony_ci /* Free the identity structure */ 23013498266Sopenharmony_ci Curl_sspi_free_identity(p_identity); 23113498266Sopenharmony_ci 23213498266Sopenharmony_ci /* Free the SPN */ 23313498266Sopenharmony_ci free(spn); 23413498266Sopenharmony_ci 23513498266Sopenharmony_ci return result; 23613498266Sopenharmony_ci} 23713498266Sopenharmony_ci 23813498266Sopenharmony_ci/* 23913498266Sopenharmony_ci * Curl_override_sspi_http_realm() 24013498266Sopenharmony_ci * 24113498266Sopenharmony_ci * This is used to populate the domain in a SSPI identity structure 24213498266Sopenharmony_ci * The realm is extracted from the challenge message and used as the 24313498266Sopenharmony_ci * domain if it is not already explicitly set. 24413498266Sopenharmony_ci * 24513498266Sopenharmony_ci * Parameters: 24613498266Sopenharmony_ci * 24713498266Sopenharmony_ci * chlg [in] - The challenge message. 24813498266Sopenharmony_ci * identity [in/out] - The identity structure. 24913498266Sopenharmony_ci * 25013498266Sopenharmony_ci * Returns CURLE_OK on success. 25113498266Sopenharmony_ci */ 25213498266Sopenharmony_ciCURLcode Curl_override_sspi_http_realm(const char *chlg, 25313498266Sopenharmony_ci SEC_WINNT_AUTH_IDENTITY *identity) 25413498266Sopenharmony_ci{ 25513498266Sopenharmony_ci xcharp_u domain, dup_domain; 25613498266Sopenharmony_ci 25713498266Sopenharmony_ci /* If domain is blank or unset, check challenge message for realm */ 25813498266Sopenharmony_ci if(!identity->Domain || !identity->DomainLength) { 25913498266Sopenharmony_ci for(;;) { 26013498266Sopenharmony_ci char value[DIGEST_MAX_VALUE_LENGTH]; 26113498266Sopenharmony_ci char content[DIGEST_MAX_CONTENT_LENGTH]; 26213498266Sopenharmony_ci 26313498266Sopenharmony_ci /* Pass all additional spaces here */ 26413498266Sopenharmony_ci while(*chlg && ISBLANK(*chlg)) 26513498266Sopenharmony_ci chlg++; 26613498266Sopenharmony_ci 26713498266Sopenharmony_ci /* Extract a value=content pair */ 26813498266Sopenharmony_ci if(Curl_auth_digest_get_pair(chlg, value, content, &chlg)) { 26913498266Sopenharmony_ci if(strcasecompare(value, "realm")) { 27013498266Sopenharmony_ci 27113498266Sopenharmony_ci /* Setup identity's domain and length */ 27213498266Sopenharmony_ci domain.tchar_ptr = curlx_convert_UTF8_to_tchar((char *) content); 27313498266Sopenharmony_ci if(!domain.tchar_ptr) 27413498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 27513498266Sopenharmony_ci 27613498266Sopenharmony_ci dup_domain.tchar_ptr = _tcsdup(domain.tchar_ptr); 27713498266Sopenharmony_ci if(!dup_domain.tchar_ptr) { 27813498266Sopenharmony_ci curlx_unicodefree(domain.tchar_ptr); 27913498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 28013498266Sopenharmony_ci } 28113498266Sopenharmony_ci 28213498266Sopenharmony_ci free(identity->Domain); 28313498266Sopenharmony_ci identity->Domain = dup_domain.tbyte_ptr; 28413498266Sopenharmony_ci identity->DomainLength = curlx_uztoul(_tcslen(dup_domain.tchar_ptr)); 28513498266Sopenharmony_ci dup_domain.tchar_ptr = NULL; 28613498266Sopenharmony_ci 28713498266Sopenharmony_ci curlx_unicodefree(domain.tchar_ptr); 28813498266Sopenharmony_ci } 28913498266Sopenharmony_ci else { 29013498266Sopenharmony_ci /* Unknown specifier, ignore it! */ 29113498266Sopenharmony_ci } 29213498266Sopenharmony_ci } 29313498266Sopenharmony_ci else 29413498266Sopenharmony_ci break; /* We're done here */ 29513498266Sopenharmony_ci 29613498266Sopenharmony_ci /* Pass all additional spaces here */ 29713498266Sopenharmony_ci while(*chlg && ISBLANK(*chlg)) 29813498266Sopenharmony_ci chlg++; 29913498266Sopenharmony_ci 30013498266Sopenharmony_ci /* Allow the list to be comma-separated */ 30113498266Sopenharmony_ci if(',' == *chlg) 30213498266Sopenharmony_ci chlg++; 30313498266Sopenharmony_ci } 30413498266Sopenharmony_ci } 30513498266Sopenharmony_ci 30613498266Sopenharmony_ci return CURLE_OK; 30713498266Sopenharmony_ci} 30813498266Sopenharmony_ci 30913498266Sopenharmony_ci/* 31013498266Sopenharmony_ci * Curl_auth_decode_digest_http_message() 31113498266Sopenharmony_ci * 31213498266Sopenharmony_ci * This is used to decode an HTTP DIGEST challenge message into the separate 31313498266Sopenharmony_ci * attributes. 31413498266Sopenharmony_ci * 31513498266Sopenharmony_ci * Parameters: 31613498266Sopenharmony_ci * 31713498266Sopenharmony_ci * chlg [in] - The challenge message. 31813498266Sopenharmony_ci * digest [in/out] - The digest data struct being used and modified. 31913498266Sopenharmony_ci * 32013498266Sopenharmony_ci * Returns CURLE_OK on success. 32113498266Sopenharmony_ci */ 32213498266Sopenharmony_ciCURLcode Curl_auth_decode_digest_http_message(const char *chlg, 32313498266Sopenharmony_ci struct digestdata *digest) 32413498266Sopenharmony_ci{ 32513498266Sopenharmony_ci size_t chlglen = strlen(chlg); 32613498266Sopenharmony_ci 32713498266Sopenharmony_ci /* We had an input token before so if there's another one now that means we 32813498266Sopenharmony_ci provided bad credentials in the previous request or it's stale. */ 32913498266Sopenharmony_ci if(digest->input_token) { 33013498266Sopenharmony_ci bool stale = false; 33113498266Sopenharmony_ci const char *p = chlg; 33213498266Sopenharmony_ci 33313498266Sopenharmony_ci /* Check for the 'stale' directive */ 33413498266Sopenharmony_ci for(;;) { 33513498266Sopenharmony_ci char value[DIGEST_MAX_VALUE_LENGTH]; 33613498266Sopenharmony_ci char content[DIGEST_MAX_CONTENT_LENGTH]; 33713498266Sopenharmony_ci 33813498266Sopenharmony_ci while(*p && ISBLANK(*p)) 33913498266Sopenharmony_ci p++; 34013498266Sopenharmony_ci 34113498266Sopenharmony_ci if(!Curl_auth_digest_get_pair(p, value, content, &p)) 34213498266Sopenharmony_ci break; 34313498266Sopenharmony_ci 34413498266Sopenharmony_ci if(strcasecompare(value, "stale") && 34513498266Sopenharmony_ci strcasecompare(content, "true")) { 34613498266Sopenharmony_ci stale = true; 34713498266Sopenharmony_ci break; 34813498266Sopenharmony_ci } 34913498266Sopenharmony_ci 35013498266Sopenharmony_ci while(*p && ISBLANK(*p)) 35113498266Sopenharmony_ci p++; 35213498266Sopenharmony_ci 35313498266Sopenharmony_ci if(',' == *p) 35413498266Sopenharmony_ci p++; 35513498266Sopenharmony_ci } 35613498266Sopenharmony_ci 35713498266Sopenharmony_ci if(stale) 35813498266Sopenharmony_ci Curl_auth_digest_cleanup(digest); 35913498266Sopenharmony_ci else 36013498266Sopenharmony_ci return CURLE_LOGIN_DENIED; 36113498266Sopenharmony_ci } 36213498266Sopenharmony_ci 36313498266Sopenharmony_ci /* Store the challenge for use later */ 36413498266Sopenharmony_ci digest->input_token = (BYTE *) Curl_memdup(chlg, chlglen + 1); 36513498266Sopenharmony_ci if(!digest->input_token) 36613498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 36713498266Sopenharmony_ci 36813498266Sopenharmony_ci digest->input_token_len = chlglen; 36913498266Sopenharmony_ci 37013498266Sopenharmony_ci return CURLE_OK; 37113498266Sopenharmony_ci} 37213498266Sopenharmony_ci 37313498266Sopenharmony_ci/* 37413498266Sopenharmony_ci * Curl_auth_create_digest_http_message() 37513498266Sopenharmony_ci * 37613498266Sopenharmony_ci * This is used to generate an HTTP DIGEST response message ready for sending 37713498266Sopenharmony_ci * to the recipient. 37813498266Sopenharmony_ci * 37913498266Sopenharmony_ci * Parameters: 38013498266Sopenharmony_ci * 38113498266Sopenharmony_ci * data [in] - The session handle. 38213498266Sopenharmony_ci * userp [in] - The user name in the format User or Domain\User. 38313498266Sopenharmony_ci * passwdp [in] - The user's password. 38413498266Sopenharmony_ci * request [in] - The HTTP request. 38513498266Sopenharmony_ci * uripath [in] - The path of the HTTP uri. 38613498266Sopenharmony_ci * digest [in/out] - The digest data struct being used and modified. 38713498266Sopenharmony_ci * outptr [in/out] - The address where a pointer to newly allocated memory 38813498266Sopenharmony_ci * holding the result will be stored upon completion. 38913498266Sopenharmony_ci * outlen [out] - The length of the output message. 39013498266Sopenharmony_ci * 39113498266Sopenharmony_ci * Returns CURLE_OK on success. 39213498266Sopenharmony_ci */ 39313498266Sopenharmony_ciCURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, 39413498266Sopenharmony_ci const char *userp, 39513498266Sopenharmony_ci const char *passwdp, 39613498266Sopenharmony_ci const unsigned char *request, 39713498266Sopenharmony_ci const unsigned char *uripath, 39813498266Sopenharmony_ci struct digestdata *digest, 39913498266Sopenharmony_ci char **outptr, size_t *outlen) 40013498266Sopenharmony_ci{ 40113498266Sopenharmony_ci size_t token_max; 40213498266Sopenharmony_ci char *resp; 40313498266Sopenharmony_ci BYTE *output_token; 40413498266Sopenharmony_ci size_t output_token_len = 0; 40513498266Sopenharmony_ci PSecPkgInfo SecurityPackage; 40613498266Sopenharmony_ci SecBuffer chlg_buf[5]; 40713498266Sopenharmony_ci SecBufferDesc chlg_desc; 40813498266Sopenharmony_ci SECURITY_STATUS status; 40913498266Sopenharmony_ci 41013498266Sopenharmony_ci (void) data; 41113498266Sopenharmony_ci 41213498266Sopenharmony_ci /* Query the security package for DigestSSP */ 41313498266Sopenharmony_ci status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST), 41413498266Sopenharmony_ci &SecurityPackage); 41513498266Sopenharmony_ci if(status != SEC_E_OK) { 41613498266Sopenharmony_ci failf(data, "SSPI: couldn't get auth info"); 41713498266Sopenharmony_ci return CURLE_AUTH_ERROR; 41813498266Sopenharmony_ci } 41913498266Sopenharmony_ci 42013498266Sopenharmony_ci token_max = SecurityPackage->cbMaxToken; 42113498266Sopenharmony_ci 42213498266Sopenharmony_ci /* Release the package buffer as it is not required anymore */ 42313498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(SecurityPackage); 42413498266Sopenharmony_ci 42513498266Sopenharmony_ci /* Allocate the output buffer according to the max token size as indicated 42613498266Sopenharmony_ci by the security package */ 42713498266Sopenharmony_ci output_token = malloc(token_max); 42813498266Sopenharmony_ci if(!output_token) { 42913498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 43013498266Sopenharmony_ci } 43113498266Sopenharmony_ci 43213498266Sopenharmony_ci /* If the user/passwd that was used to make the identity for http_context 43313498266Sopenharmony_ci has changed then delete that context. */ 43413498266Sopenharmony_ci if((userp && !digest->user) || (!userp && digest->user) || 43513498266Sopenharmony_ci (passwdp && !digest->passwd) || (!passwdp && digest->passwd) || 43613498266Sopenharmony_ci (userp && digest->user && Curl_timestrcmp(userp, digest->user)) || 43713498266Sopenharmony_ci (passwdp && digest->passwd && Curl_timestrcmp(passwdp, digest->passwd))) { 43813498266Sopenharmony_ci if(digest->http_context) { 43913498266Sopenharmony_ci s_pSecFn->DeleteSecurityContext(digest->http_context); 44013498266Sopenharmony_ci Curl_safefree(digest->http_context); 44113498266Sopenharmony_ci } 44213498266Sopenharmony_ci Curl_safefree(digest->user); 44313498266Sopenharmony_ci Curl_safefree(digest->passwd); 44413498266Sopenharmony_ci } 44513498266Sopenharmony_ci 44613498266Sopenharmony_ci if(digest->http_context) { 44713498266Sopenharmony_ci chlg_desc.ulVersion = SECBUFFER_VERSION; 44813498266Sopenharmony_ci chlg_desc.cBuffers = 5; 44913498266Sopenharmony_ci chlg_desc.pBuffers = chlg_buf; 45013498266Sopenharmony_ci chlg_buf[0].BufferType = SECBUFFER_TOKEN; 45113498266Sopenharmony_ci chlg_buf[0].pvBuffer = NULL; 45213498266Sopenharmony_ci chlg_buf[0].cbBuffer = 0; 45313498266Sopenharmony_ci chlg_buf[1].BufferType = SECBUFFER_PKG_PARAMS; 45413498266Sopenharmony_ci chlg_buf[1].pvBuffer = (void *) request; 45513498266Sopenharmony_ci chlg_buf[1].cbBuffer = curlx_uztoul(strlen((const char *) request)); 45613498266Sopenharmony_ci chlg_buf[2].BufferType = SECBUFFER_PKG_PARAMS; 45713498266Sopenharmony_ci chlg_buf[2].pvBuffer = (void *) uripath; 45813498266Sopenharmony_ci chlg_buf[2].cbBuffer = curlx_uztoul(strlen((const char *) uripath)); 45913498266Sopenharmony_ci chlg_buf[3].BufferType = SECBUFFER_PKG_PARAMS; 46013498266Sopenharmony_ci chlg_buf[3].pvBuffer = NULL; 46113498266Sopenharmony_ci chlg_buf[3].cbBuffer = 0; 46213498266Sopenharmony_ci chlg_buf[4].BufferType = SECBUFFER_PADDING; 46313498266Sopenharmony_ci chlg_buf[4].pvBuffer = output_token; 46413498266Sopenharmony_ci chlg_buf[4].cbBuffer = curlx_uztoul(token_max); 46513498266Sopenharmony_ci 46613498266Sopenharmony_ci status = s_pSecFn->MakeSignature(digest->http_context, 0, &chlg_desc, 0); 46713498266Sopenharmony_ci if(status == SEC_E_OK) 46813498266Sopenharmony_ci output_token_len = chlg_buf[4].cbBuffer; 46913498266Sopenharmony_ci else { /* delete the context so a new one can be made */ 47013498266Sopenharmony_ci infof(data, "digest_sspi: MakeSignature failed, error 0x%08lx", 47113498266Sopenharmony_ci (long)status); 47213498266Sopenharmony_ci s_pSecFn->DeleteSecurityContext(digest->http_context); 47313498266Sopenharmony_ci Curl_safefree(digest->http_context); 47413498266Sopenharmony_ci } 47513498266Sopenharmony_ci } 47613498266Sopenharmony_ci 47713498266Sopenharmony_ci if(!digest->http_context) { 47813498266Sopenharmony_ci CredHandle credentials; 47913498266Sopenharmony_ci SEC_WINNT_AUTH_IDENTITY identity; 48013498266Sopenharmony_ci SEC_WINNT_AUTH_IDENTITY *p_identity; 48113498266Sopenharmony_ci SecBuffer resp_buf; 48213498266Sopenharmony_ci SecBufferDesc resp_desc; 48313498266Sopenharmony_ci unsigned long attrs; 48413498266Sopenharmony_ci TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ 48513498266Sopenharmony_ci TCHAR *spn; 48613498266Sopenharmony_ci 48713498266Sopenharmony_ci /* free the copy of user/passwd used to make the previous identity */ 48813498266Sopenharmony_ci Curl_safefree(digest->user); 48913498266Sopenharmony_ci Curl_safefree(digest->passwd); 49013498266Sopenharmony_ci 49113498266Sopenharmony_ci if(userp && *userp) { 49213498266Sopenharmony_ci /* Populate our identity structure */ 49313498266Sopenharmony_ci if(Curl_create_sspi_identity(userp, passwdp, &identity)) { 49413498266Sopenharmony_ci free(output_token); 49513498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 49613498266Sopenharmony_ci } 49713498266Sopenharmony_ci 49813498266Sopenharmony_ci /* Populate our identity domain */ 49913498266Sopenharmony_ci if(Curl_override_sspi_http_realm((const char *) digest->input_token, 50013498266Sopenharmony_ci &identity)) { 50113498266Sopenharmony_ci free(output_token); 50213498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 50313498266Sopenharmony_ci } 50413498266Sopenharmony_ci 50513498266Sopenharmony_ci /* Allow proper cleanup of the identity structure */ 50613498266Sopenharmony_ci p_identity = &identity; 50713498266Sopenharmony_ci } 50813498266Sopenharmony_ci else 50913498266Sopenharmony_ci /* Use the current Windows user */ 51013498266Sopenharmony_ci p_identity = NULL; 51113498266Sopenharmony_ci 51213498266Sopenharmony_ci if(userp) { 51313498266Sopenharmony_ci digest->user = strdup(userp); 51413498266Sopenharmony_ci 51513498266Sopenharmony_ci if(!digest->user) { 51613498266Sopenharmony_ci free(output_token); 51713498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 51813498266Sopenharmony_ci } 51913498266Sopenharmony_ci } 52013498266Sopenharmony_ci 52113498266Sopenharmony_ci if(passwdp) { 52213498266Sopenharmony_ci digest->passwd = strdup(passwdp); 52313498266Sopenharmony_ci 52413498266Sopenharmony_ci if(!digest->passwd) { 52513498266Sopenharmony_ci free(output_token); 52613498266Sopenharmony_ci Curl_safefree(digest->user); 52713498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 52813498266Sopenharmony_ci } 52913498266Sopenharmony_ci } 53013498266Sopenharmony_ci 53113498266Sopenharmony_ci /* Acquire our credentials handle */ 53213498266Sopenharmony_ci status = s_pSecFn->AcquireCredentialsHandle(NULL, 53313498266Sopenharmony_ci (TCHAR *) TEXT(SP_NAME_DIGEST), 53413498266Sopenharmony_ci SECPKG_CRED_OUTBOUND, NULL, 53513498266Sopenharmony_ci p_identity, NULL, NULL, 53613498266Sopenharmony_ci &credentials, &expiry); 53713498266Sopenharmony_ci if(status != SEC_E_OK) { 53813498266Sopenharmony_ci Curl_sspi_free_identity(p_identity); 53913498266Sopenharmony_ci free(output_token); 54013498266Sopenharmony_ci 54113498266Sopenharmony_ci return CURLE_LOGIN_DENIED; 54213498266Sopenharmony_ci } 54313498266Sopenharmony_ci 54413498266Sopenharmony_ci /* Setup the challenge "input" security buffer if present */ 54513498266Sopenharmony_ci chlg_desc.ulVersion = SECBUFFER_VERSION; 54613498266Sopenharmony_ci chlg_desc.cBuffers = 3; 54713498266Sopenharmony_ci chlg_desc.pBuffers = chlg_buf; 54813498266Sopenharmony_ci chlg_buf[0].BufferType = SECBUFFER_TOKEN; 54913498266Sopenharmony_ci chlg_buf[0].pvBuffer = digest->input_token; 55013498266Sopenharmony_ci chlg_buf[0].cbBuffer = curlx_uztoul(digest->input_token_len); 55113498266Sopenharmony_ci chlg_buf[1].BufferType = SECBUFFER_PKG_PARAMS; 55213498266Sopenharmony_ci chlg_buf[1].pvBuffer = (void *) request; 55313498266Sopenharmony_ci chlg_buf[1].cbBuffer = curlx_uztoul(strlen((const char *) request)); 55413498266Sopenharmony_ci chlg_buf[2].BufferType = SECBUFFER_PKG_PARAMS; 55513498266Sopenharmony_ci chlg_buf[2].pvBuffer = NULL; 55613498266Sopenharmony_ci chlg_buf[2].cbBuffer = 0; 55713498266Sopenharmony_ci 55813498266Sopenharmony_ci /* Setup the response "output" security buffer */ 55913498266Sopenharmony_ci resp_desc.ulVersion = SECBUFFER_VERSION; 56013498266Sopenharmony_ci resp_desc.cBuffers = 1; 56113498266Sopenharmony_ci resp_desc.pBuffers = &resp_buf; 56213498266Sopenharmony_ci resp_buf.BufferType = SECBUFFER_TOKEN; 56313498266Sopenharmony_ci resp_buf.pvBuffer = output_token; 56413498266Sopenharmony_ci resp_buf.cbBuffer = curlx_uztoul(token_max); 56513498266Sopenharmony_ci 56613498266Sopenharmony_ci spn = curlx_convert_UTF8_to_tchar((char *) uripath); 56713498266Sopenharmony_ci if(!spn) { 56813498266Sopenharmony_ci s_pSecFn->FreeCredentialsHandle(&credentials); 56913498266Sopenharmony_ci 57013498266Sopenharmony_ci Curl_sspi_free_identity(p_identity); 57113498266Sopenharmony_ci free(output_token); 57213498266Sopenharmony_ci 57313498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 57413498266Sopenharmony_ci } 57513498266Sopenharmony_ci 57613498266Sopenharmony_ci /* Allocate our new context handle */ 57713498266Sopenharmony_ci digest->http_context = calloc(1, sizeof(CtxtHandle)); 57813498266Sopenharmony_ci if(!digest->http_context) 57913498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 58013498266Sopenharmony_ci 58113498266Sopenharmony_ci /* Generate our response message */ 58213498266Sopenharmony_ci status = s_pSecFn->InitializeSecurityContext(&credentials, NULL, 58313498266Sopenharmony_ci spn, 58413498266Sopenharmony_ci ISC_REQ_USE_HTTP_STYLE, 0, 0, 58513498266Sopenharmony_ci &chlg_desc, 0, 58613498266Sopenharmony_ci digest->http_context, 58713498266Sopenharmony_ci &resp_desc, &attrs, &expiry); 58813498266Sopenharmony_ci curlx_unicodefree(spn); 58913498266Sopenharmony_ci 59013498266Sopenharmony_ci if(status == SEC_I_COMPLETE_NEEDED || 59113498266Sopenharmony_ci status == SEC_I_COMPLETE_AND_CONTINUE) 59213498266Sopenharmony_ci s_pSecFn->CompleteAuthToken(&credentials, &resp_desc); 59313498266Sopenharmony_ci else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { 59413498266Sopenharmony_ci#if !defined(CURL_DISABLE_VERBOSE_STRINGS) 59513498266Sopenharmony_ci char buffer[STRERROR_LEN]; 59613498266Sopenharmony_ci#endif 59713498266Sopenharmony_ci 59813498266Sopenharmony_ci s_pSecFn->FreeCredentialsHandle(&credentials); 59913498266Sopenharmony_ci 60013498266Sopenharmony_ci Curl_sspi_free_identity(p_identity); 60113498266Sopenharmony_ci free(output_token); 60213498266Sopenharmony_ci 60313498266Sopenharmony_ci Curl_safefree(digest->http_context); 60413498266Sopenharmony_ci 60513498266Sopenharmony_ci if(status == SEC_E_INSUFFICIENT_MEMORY) 60613498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 60713498266Sopenharmony_ci 60813498266Sopenharmony_ci#if !defined(CURL_DISABLE_VERBOSE_STRINGS) 60913498266Sopenharmony_ci infof(data, "schannel: InitializeSecurityContext failed: %s", 61013498266Sopenharmony_ci Curl_sspi_strerror(status, buffer, sizeof(buffer))); 61113498266Sopenharmony_ci#endif 61213498266Sopenharmony_ci 61313498266Sopenharmony_ci return CURLE_AUTH_ERROR; 61413498266Sopenharmony_ci } 61513498266Sopenharmony_ci 61613498266Sopenharmony_ci output_token_len = resp_buf.cbBuffer; 61713498266Sopenharmony_ci 61813498266Sopenharmony_ci s_pSecFn->FreeCredentialsHandle(&credentials); 61913498266Sopenharmony_ci Curl_sspi_free_identity(p_identity); 62013498266Sopenharmony_ci } 62113498266Sopenharmony_ci 62213498266Sopenharmony_ci resp = malloc(output_token_len + 1); 62313498266Sopenharmony_ci if(!resp) { 62413498266Sopenharmony_ci free(output_token); 62513498266Sopenharmony_ci 62613498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 62713498266Sopenharmony_ci } 62813498266Sopenharmony_ci 62913498266Sopenharmony_ci /* Copy the generated response */ 63013498266Sopenharmony_ci memcpy(resp, output_token, output_token_len); 63113498266Sopenharmony_ci resp[output_token_len] = 0; 63213498266Sopenharmony_ci 63313498266Sopenharmony_ci /* Return the response */ 63413498266Sopenharmony_ci *outptr = resp; 63513498266Sopenharmony_ci *outlen = output_token_len; 63613498266Sopenharmony_ci 63713498266Sopenharmony_ci /* Free the response buffer */ 63813498266Sopenharmony_ci free(output_token); 63913498266Sopenharmony_ci 64013498266Sopenharmony_ci return CURLE_OK; 64113498266Sopenharmony_ci} 64213498266Sopenharmony_ci 64313498266Sopenharmony_ci/* 64413498266Sopenharmony_ci * Curl_auth_digest_cleanup() 64513498266Sopenharmony_ci * 64613498266Sopenharmony_ci * This is used to clean up the digest specific data. 64713498266Sopenharmony_ci * 64813498266Sopenharmony_ci * Parameters: 64913498266Sopenharmony_ci * 65013498266Sopenharmony_ci * digest [in/out] - The digest data struct being cleaned up. 65113498266Sopenharmony_ci * 65213498266Sopenharmony_ci */ 65313498266Sopenharmony_civoid Curl_auth_digest_cleanup(struct digestdata *digest) 65413498266Sopenharmony_ci{ 65513498266Sopenharmony_ci /* Free the input token */ 65613498266Sopenharmony_ci Curl_safefree(digest->input_token); 65713498266Sopenharmony_ci 65813498266Sopenharmony_ci /* Reset any variables */ 65913498266Sopenharmony_ci digest->input_token_len = 0; 66013498266Sopenharmony_ci 66113498266Sopenharmony_ci /* Delete security context */ 66213498266Sopenharmony_ci if(digest->http_context) { 66313498266Sopenharmony_ci s_pSecFn->DeleteSecurityContext(digest->http_context); 66413498266Sopenharmony_ci Curl_safefree(digest->http_context); 66513498266Sopenharmony_ci } 66613498266Sopenharmony_ci 66713498266Sopenharmony_ci /* Free the copy of user/passwd used to make the identity for http_context */ 66813498266Sopenharmony_ci Curl_safefree(digest->user); 66913498266Sopenharmony_ci Curl_safefree(digest->passwd); 67013498266Sopenharmony_ci} 67113498266Sopenharmony_ci 67213498266Sopenharmony_ci#endif /* USE_WINDOWS_SSPI && !CURL_DISABLE_DIGEST_AUTH */ 673