123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702 |
- #include "curl_setup.h"
- #include <curl/curl.h>
- #include "urldata.h"
- #include "curl_base64.h"
- #include "curl_md5.h"
- #include "vtls/vtls.h"
- #include "curl_hmac.h"
- #include "curl_ntlm_msgs.h"
- #include "curl_sasl.h"
- #include "warnless.h"
- #include "curl_memory.h"
- #include "strtok.h"
- #include "rawstr.h"
- #ifdef USE_NSS
- #include "vtls/nssg.h"
- #endif
- #define _MPRINTF_REPLACE
- #include <curl/mprintf.h>
- #include "memdebug.h"
- #if !defined(CURL_DISABLE_CRYPTO_AUTH) && !defined(USE_WINDOWS_SSPI)
- #define DIGEST_QOP_VALUE_AUTH (1 << 0)
- #define DIGEST_QOP_VALUE_AUTH_INT (1 << 1)
- #define DIGEST_QOP_VALUE_AUTH_CONF (1 << 2)
- #define DIGEST_QOP_VALUE_STRING_AUTH "auth"
- #define DIGEST_QOP_VALUE_STRING_AUTH_INT "auth-int"
- #define DIGEST_QOP_VALUE_STRING_AUTH_CONF "auth-conf"
- static bool sasl_digest_get_key_value(const char *chlg,
- const char *key,
- char *value,
- size_t max_val_len,
- char end_char)
- {
- char *find_pos;
- size_t i;
- find_pos = strstr(chlg, key);
- if(!find_pos)
- return FALSE;
- find_pos += strlen(key);
- for(i = 0; *find_pos && *find_pos != end_char && i < max_val_len - 1; ++i)
- value[i] = *find_pos++;
- value[i] = '\0';
- return TRUE;
- }
- static CURLcode sasl_digest_get_qop_values(const char *options, int *value)
- {
- char *tmp;
- char *token;
- char *tok_buf;
-
- *value = 0;
-
- tmp = strdup(options);
- if(!tmp)
- return CURLE_OUT_OF_MEMORY;
- token = strtok_r(tmp, ",", &tok_buf);
- while(token != NULL) {
- if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH))
- *value |= DIGEST_QOP_VALUE_AUTH;
- else if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH_INT))
- *value |= DIGEST_QOP_VALUE_AUTH_INT;
- else if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH_CONF))
- *value |= DIGEST_QOP_VALUE_AUTH_CONF;
- token = strtok_r(NULL, ",", &tok_buf);
- }
- Curl_safefree(tmp);
- return CURLE_OK;
- }
- #endif
- CURLcode Curl_sasl_create_plain_message(struct SessionHandle *data,
- const char *userp,
- const char *passwdp,
- char **outptr, size_t *outlen)
- {
- CURLcode result;
- char *plainauth;
- size_t ulen;
- size_t plen;
- ulen = strlen(userp);
- plen = strlen(passwdp);
- plainauth = malloc(2 * ulen + plen + 2);
- if(!plainauth) {
- *outlen = 0;
- *outptr = NULL;
- return CURLE_OUT_OF_MEMORY;
- }
-
- memcpy(plainauth, userp, ulen);
- plainauth[ulen] = '\0';
- memcpy(plainauth + ulen + 1, userp, ulen);
- plainauth[2 * ulen + 1] = '\0';
- memcpy(plainauth + 2 * ulen + 2, passwdp, plen);
-
- result = Curl_base64_encode(data, plainauth, 2 * ulen + plen + 2, outptr,
- outlen);
- Curl_safefree(plainauth);
- return result;
- }
- CURLcode Curl_sasl_create_login_message(struct SessionHandle *data,
- const char *valuep, char **outptr,
- size_t *outlen)
- {
- size_t vlen = strlen(valuep);
- if(!vlen) {
-
- *outptr = strdup("=");
- if(*outptr) {
- *outlen = (size_t) 1;
- return CURLE_OK;
- }
- *outlen = 0;
- return CURLE_OUT_OF_MEMORY;
- }
-
- return Curl_base64_encode(data, valuep, vlen, outptr, outlen);
- }
- #ifndef CURL_DISABLE_CRYPTO_AUTH
-
- CURLcode Curl_sasl_decode_cram_md5_message(const char *chlg64, char **outptr,
- size_t *outlen)
- {
- CURLcode result = CURLE_OK;
- size_t chlg64len = strlen(chlg64);
- *outptr = NULL;
- *outlen = 0;
-
- if(chlg64len && *chlg64 != '=')
- result = Curl_base64_decode(chlg64, (unsigned char **) outptr, outlen);
- return result;
- }
-
- CURLcode Curl_sasl_create_cram_md5_message(struct SessionHandle *data,
- const char *chlg,
- const char *userp,
- const char *passwdp,
- char **outptr, size_t *outlen)
- {
- CURLcode result = CURLE_OK;
- size_t chlglen = 0;
- HMAC_context *ctxt;
- unsigned char digest[MD5_DIGEST_LEN];
- char *response;
- if(chlg)
- chlglen = strlen(chlg);
-
- ctxt = Curl_HMAC_init(Curl_HMAC_MD5,
- (const unsigned char *) passwdp,
- curlx_uztoui(strlen(passwdp)));
- if(!ctxt)
- return CURLE_OUT_OF_MEMORY;
-
- if(chlglen > 0)
- Curl_HMAC_update(ctxt, (const unsigned char *) chlg,
- curlx_uztoui(chlglen));
-
- Curl_HMAC_final(ctxt, digest);
-
- response = aprintf(
- "%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
- userp, digest[0], digest[1], digest[2], digest[3], digest[4],
- digest[5], digest[6], digest[7], digest[8], digest[9], digest[10],
- digest[11], digest[12], digest[13], digest[14], digest[15]);
- if(!response)
- return CURLE_OUT_OF_MEMORY;
-
- result = Curl_base64_encode(data, response, 0, outptr, outlen);
- Curl_safefree(response);
- return result;
- }
- #ifndef USE_WINDOWS_SSPI
- static CURLcode sasl_decode_digest_md5_message(const char *chlg64,
- char *nonce, size_t nlen,
- char *realm, size_t rlen,
- char *alg, size_t alen,
- char *qop, size_t qlen)
- {
- CURLcode result = CURLE_OK;
- unsigned char *chlg = NULL;
- size_t chlglen = 0;
- size_t chlg64len = strlen(chlg64);
-
- if(chlg64len && *chlg64 != '=') {
- result = Curl_base64_decode(chlg64, &chlg, &chlglen);
- if(result)
- return result;
- }
-
- if(!chlg)
- return CURLE_BAD_CONTENT_ENCODING;
-
- if(!sasl_digest_get_key_value((char *)chlg, "nonce=\"", nonce, nlen, '\"')) {
- Curl_safefree(chlg);
- return CURLE_BAD_CONTENT_ENCODING;
- }
-
- if(!sasl_digest_get_key_value((char *)chlg, "realm=\"", realm, rlen, '\"')) {
-
- strcpy(realm, "");
- }
-
- if(!sasl_digest_get_key_value((char *)chlg, "algorithm=", alg, alen, ',')) {
- Curl_safefree(chlg);
- return CURLE_BAD_CONTENT_ENCODING;
- }
-
- if(!sasl_digest_get_key_value((char *)chlg, "qop=\"", qop, qlen, '\"')) {
- Curl_safefree(chlg);
- return CURLE_BAD_CONTENT_ENCODING;
- }
- Curl_safefree(chlg);
- return CURLE_OK;
- }
- CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data,
- const char *chlg64,
- const char *userp,
- const char *passwdp,
- const char *service,
- char **outptr, size_t *outlen)
- {
- CURLcode result = CURLE_OK;
- size_t i;
- MD5_context *ctxt;
- char *response = NULL;
- unsigned char digest[MD5_DIGEST_LEN];
- char HA1_hex[2 * MD5_DIGEST_LEN + 1];
- char HA2_hex[2 * MD5_DIGEST_LEN + 1];
- char resp_hash_hex[2 * MD5_DIGEST_LEN + 1];
- char nonce[64];
- char realm[128];
- char algorithm[64];
- char qop_options[64];
- int qop_values;
- char cnonce[33];
- unsigned int entropy[4];
- char nonceCount[] = "00000001";
- char method[] = "AUTHENTICATE";
- char qop[] = DIGEST_QOP_VALUE_STRING_AUTH;
- char uri[128];
-
- result = sasl_decode_digest_md5_message(chlg64, nonce, sizeof(nonce),
- realm, sizeof(realm),
- algorithm, sizeof(algorithm),
- qop_options, sizeof(qop_options));
- if(result)
- return result;
-
- if(strcmp(algorithm, "md5-sess") != 0)
- return CURLE_BAD_CONTENT_ENCODING;
-
- result = sasl_digest_get_qop_values(qop_options, &qop_values);
- if(result)
- return result;
-
- if(!(qop_values & DIGEST_QOP_VALUE_AUTH))
- return CURLE_BAD_CONTENT_ENCODING;
-
- entropy[0] = Curl_rand(data);
- entropy[1] = Curl_rand(data);
- entropy[2] = Curl_rand(data);
- entropy[3] = Curl_rand(data);
-
- snprintf(cnonce, sizeof(cnonce), "%08x%08x%08x%08x",
- entropy[0], entropy[1], entropy[2], entropy[3]);
-
- ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
- if(!ctxt)
- return CURLE_OUT_OF_MEMORY;
- Curl_MD5_update(ctxt, (const unsigned char *) userp,
- curlx_uztoui(strlen(userp)));
- Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
- Curl_MD5_update(ctxt, (const unsigned char *) realm,
- curlx_uztoui(strlen(realm)));
- Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
- Curl_MD5_update(ctxt, (const unsigned char *) passwdp,
- curlx_uztoui(strlen(passwdp)));
- Curl_MD5_final(ctxt, digest);
- ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
- if(!ctxt)
- return CURLE_OUT_OF_MEMORY;
- Curl_MD5_update(ctxt, (const unsigned char *) digest, MD5_DIGEST_LEN);
- Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
- Curl_MD5_update(ctxt, (const unsigned char *) nonce,
- curlx_uztoui(strlen(nonce)));
- Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
- Curl_MD5_update(ctxt, (const unsigned char *) cnonce,
- curlx_uztoui(strlen(cnonce)));
- Curl_MD5_final(ctxt, digest);
-
- for(i = 0; i < MD5_DIGEST_LEN; i++)
- snprintf(&HA1_hex[2 * i], 3, "%02x", digest[i]);
-
- snprintf(uri, sizeof(uri), "%s/%s", service, realm);
-
- ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
- if(!ctxt)
- return CURLE_OUT_OF_MEMORY;
- Curl_MD5_update(ctxt, (const unsigned char *) method,
- curlx_uztoui(strlen(method)));
- Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
- Curl_MD5_update(ctxt, (const unsigned char *) uri,
- curlx_uztoui(strlen(uri)));
- Curl_MD5_final(ctxt, digest);
- for(i = 0; i < MD5_DIGEST_LEN; i++)
- snprintf(&HA2_hex[2 * i], 3, "%02x", digest[i]);
-
- ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
- if(!ctxt)
- return CURLE_OUT_OF_MEMORY;
- Curl_MD5_update(ctxt, (const unsigned char *) HA1_hex, 2 * MD5_DIGEST_LEN);
- Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
- Curl_MD5_update(ctxt, (const unsigned char *) nonce,
- curlx_uztoui(strlen(nonce)));
- Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
- Curl_MD5_update(ctxt, (const unsigned char *) nonceCount,
- curlx_uztoui(strlen(nonceCount)));
- Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
- Curl_MD5_update(ctxt, (const unsigned char *) cnonce,
- curlx_uztoui(strlen(cnonce)));
- Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
- Curl_MD5_update(ctxt, (const unsigned char *) qop,
- curlx_uztoui(strlen(qop)));
- Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
- Curl_MD5_update(ctxt, (const unsigned char *) HA2_hex, 2 * MD5_DIGEST_LEN);
- Curl_MD5_final(ctxt, digest);
- for(i = 0; i < MD5_DIGEST_LEN; i++)
- snprintf(&resp_hash_hex[2 * i], 3, "%02x", digest[i]);
-
- response = aprintf("username=\"%s\",realm=\"%s\",nonce=\"%s\","
- "cnonce=\"%s\",nc=\"%s\",digest-uri=\"%s\",response=%s,"
- "qop=%s",
- userp, realm, nonce,
- cnonce, nonceCount, uri, resp_hash_hex, qop);
- if(!response)
- return CURLE_OUT_OF_MEMORY;
-
- result = Curl_base64_encode(data, response, 0, outptr, outlen);
- free(response);
- return result;
- }
- #endif
- #endif
- #ifdef USE_NTLM
- CURLcode Curl_sasl_create_ntlm_type1_message(const char *userp,
- const char *passwdp,
- struct ntlmdata *ntlm,
- char **outptr, size_t *outlen)
- {
- return Curl_ntlm_create_type1_message(userp, passwdp, ntlm, outptr, outlen);
- }
- CURLcode Curl_sasl_decode_ntlm_type2_message(struct SessionHandle *data,
- const char *type2msg,
- struct ntlmdata *ntlm)
- {
- #ifdef USE_NSS
- CURLcode result;
-
- result = Curl_nss_force_init(data);
- if(result)
- return result;
- #endif
- return Curl_ntlm_decode_type2_message(data, type2msg, ntlm);
- }
- CURLcode Curl_sasl_create_ntlm_type3_message(struct SessionHandle *data,
- const char *userp,
- const char *passwdp,
- struct ntlmdata *ntlm,
- char **outptr, size_t *outlen)
- {
- return Curl_ntlm_create_type3_message(data, userp, passwdp, ntlm, outptr,
- outlen);
- }
- #endif
- CURLcode Curl_sasl_create_xoauth2_message(struct SessionHandle *data,
- const char *user,
- const char *bearer,
- char **outptr, size_t *outlen)
- {
- CURLcode result = CURLE_OK;
- char *xoauth = NULL;
-
- xoauth = aprintf("user=%s\1auth=Bearer %s\1\1", user, bearer);
- if(!xoauth)
- return CURLE_OUT_OF_MEMORY;
-
- result = Curl_base64_encode(data, xoauth, strlen(xoauth), outptr, outlen);
- Curl_safefree(xoauth);
- return result;
- }
- void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused)
- {
- #ifdef USE_NTLM
-
- if(authused == SASL_MECH_NTLM) {
- Curl_ntlm_sspi_cleanup(&conn->ntlm);
- }
- (void)conn;
- #else
-
- (void)conn;
- (void)authused;
- #endif
- }
|