summaryrefslogtreecommitdiff
path: root/lib/curl_sasl.c
diff options
context:
space:
mode:
authorPatrick Monnerat <patrick@monnerat.net>2021-03-17 20:09:55 +0100
committerDaniel Stenberg <daniel@haxx.se>2021-04-22 09:06:07 +0200
commit19ea52da4df3c3ebc399ae25e705c7a8b5d45d95 (patch)
treea24d58a91383624c6fefb1295829b1e3b284feb7 /lib/curl_sasl.c
parent34cf40321c3cfa5160e34a87a816b7c6030c0296 (diff)
downloadcurl-19ea52da4df3c3ebc399ae25e705c7a8b5d45d95.tar.gz
vauth: factor base64 conversions out of authentication procedures
Input challenges and returned messages are now in binary. Conversions from/to base64 are performed by callers (currently curl_sasl.c and http_ntlm.c). Closes #6654
Diffstat (limited to 'lib/curl_sasl.c')
-rw-r--r--lib/curl_sasl.c241
1 files changed, 140 insertions, 101 deletions
diff --git a/lib/curl_sasl.c b/lib/curl_sasl.c
index 2cba18547..164bf00a0 100644
--- a/lib/curl_sasl.c
+++ b/lib/curl_sasl.c
@@ -242,6 +242,49 @@ static void state(struct SASL *sasl, struct Curl_easy *data,
sasl->state = newstate;
}
+/* Get the SASL server message and convert it to binary. */
+static CURLcode get_server_message(struct SASL *sasl, struct Curl_easy *data,
+ struct bufref *out)
+{
+ unsigned char *msg;
+ size_t msglen;
+ char *serverdata = NULL;
+ CURLcode result = CURLE_OK;
+
+ sasl->params->getmessage(data->state.buffer, &serverdata);
+ if(!serverdata)
+ result = CURLE_BAD_CONTENT_ENCODING;
+ else if(!*serverdata || *serverdata == '=')
+ Curl_bufref_set(out, NULL, 0, NULL);
+ else {
+ result = Curl_base64_decode(serverdata, &msg, &msglen);
+ if(!result)
+ Curl_bufref_set(out, msg, msglen, curl_free);
+ }
+ return result;
+}
+
+/* Encode the outgoing SASL message. */
+static CURLcode build_message(struct Curl_easy *data, struct bufref *msg)
+{
+ CURLcode result = CURLE_OK;
+ char *base64;
+ size_t base64len;
+
+ if(!Curl_bufref_ptr(msg)) /* Empty mesage. */
+ Curl_bufref_set(msg, "", 0, NULL);
+ else if(!Curl_bufref_len(msg)) /* Explicit empty response. */
+ Curl_bufref_set(msg, "=", 1, NULL);
+ else {
+ result = Curl_base64_encode(data, (const char *) Curl_bufref_ptr(msg),
+ Curl_bufref_len(msg), &base64, &base64len);
+ if(!result)
+ Curl_bufref_set(msg, base64, base64len, curl_free);
+ }
+
+ return result;
+}
+
/*
* Curl_sasl_can_authenticate()
*
@@ -272,8 +315,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
CURLcode result = CURLE_OK;
unsigned int enabledmechs;
const char *mech = NULL;
- char *resp = NULL;
- size_t len = 0;
+ struct bufref resp;
saslstate state1 = SASL_STOP;
saslstate state2 = SASL_FINAL;
#ifndef CURL_DISABLE_PROXY
@@ -290,7 +332,10 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
sasl->params->service;
#endif
const char *oauth_bearer = data->set.str[STRING_BEARER];
+ struct bufref nullmsg;
+ Curl_bufref_init(&nullmsg);
+ Curl_bufref_init(&resp);
sasl->force_ir = force_ir; /* Latch for future use */
sasl->authused = 0; /* No mechanism used yet */
enabledmechs = sasl->authmechs & sasl->prefmech;
@@ -304,8 +349,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
sasl->authused = SASL_MECH_EXTERNAL;
if(force_ir || data->set.sasl_ir)
- result = Curl_auth_create_external_message(data, conn->user, &resp,
- &len);
+ result = Curl_auth_create_external_message(conn->user, &resp);
}
else if(conn->bits.user_passwd) {
#if defined(USE_KERBEROS5)
@@ -321,10 +365,10 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
result = Curl_auth_create_gssapi_user_message(data, conn->user,
conn->passwd,
service,
- data->conn->host.name,
+ conn->host.name,
sasl->mutual_auth,
NULL, &conn->krb5,
- &resp, &len);
+ &resp);
}
else
#endif
@@ -340,8 +384,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
result = Curl_auth_gsasl_start(data, conn->user,
conn->passwd, &conn->gsasl);
if(result == CURLE_OK && (force_ir || data->set.sasl_ir))
- result = Curl_auth_gsasl_token(data, NULL, &conn->gsasl,
- &resp, &len);
+ result = Curl_auth_gsasl_token(data, &nullmsg, &conn->gsasl, &resp);
}
else if((enabledmechs & SASL_MECH_SCRAM_SHA_1) &&
Curl_auth_gsasl_is_supported(data, SASL_MECH_STRING_SCRAM_SHA_1,
@@ -354,8 +397,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
result = Curl_auth_gsasl_start(data, conn->user,
conn->passwd, &conn->gsasl);
if(result == CURLE_OK && (force_ir || data->set.sasl_ir))
- result = Curl_auth_gsasl_token(data, NULL, &conn->gsasl,
- &resp, &len);
+ result = Curl_auth_gsasl_token(data, &nullmsg, &conn->gsasl, &resp);
}
else
#endif
@@ -385,8 +427,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
conn->user, conn->passwd,
service,
hostname,
- &conn->ntlm, &resp,
- &len);
+ &conn->ntlm, &resp);
}
else
#endif
@@ -397,11 +438,11 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
sasl->authused = SASL_MECH_OAUTHBEARER;
if(force_ir || data->set.sasl_ir)
- result = Curl_auth_create_oauth_bearer_message(data, conn->user,
+ result = Curl_auth_create_oauth_bearer_message(conn->user,
hostname,
port,
oauth_bearer,
- &resp, &len);
+ &resp);
}
else if((enabledmechs & SASL_MECH_XOAUTH2) && oauth_bearer) {
mech = SASL_MECH_STRING_XOAUTH2;
@@ -409,9 +450,9 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
sasl->authused = SASL_MECH_XOAUTH2;
if(force_ir || data->set.sasl_ir)
- result = Curl_auth_create_xoauth_bearer_message(data, conn->user,
+ result = Curl_auth_create_xoauth_bearer_message(conn->user,
oauth_bearer,
- &resp, &len);
+ &resp);
}
else if(enabledmechs & SASL_MECH_PLAIN) {
mech = SASL_MECH_STRING_PLAIN;
@@ -419,9 +460,9 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
sasl->authused = SASL_MECH_PLAIN;
if(force_ir || data->set.sasl_ir)
- result = Curl_auth_create_plain_message(data, conn->sasl_authzid,
+ result = Curl_auth_create_plain_message(conn->sasl_authzid,
conn->user, conn->passwd,
- &resp, &len);
+ &resp);
}
else if(enabledmechs & SASL_MECH_LOGIN) {
mech = SASL_MECH_STRING_LOGIN;
@@ -430,26 +471,29 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
sasl->authused = SASL_MECH_LOGIN;
if(force_ir || data->set.sasl_ir)
- result = Curl_auth_create_login_message(data, conn->user, &resp, &len);
+ result = Curl_auth_create_login_message(conn->user, &resp);
}
}
if(!result && mech) {
- if(resp && sasl->params->maxirlen &&
- strlen(mech) + len > sasl->params->maxirlen) {
- free(resp);
- resp = NULL;
- }
+ if(Curl_bufref_ptr(&resp))
+ result = build_message(data, &resp);
+
+ if(sasl->params->maxirlen &&
+ strlen(mech) + Curl_bufref_len(&resp) > sasl->params->maxirlen)
+ Curl_bufref_free(&resp);
+
+ if(!result)
+ result = sasl->params->sendauth(data, conn, mech,
+ (const char *) Curl_bufref_ptr(&resp));
- result = sasl->params->sendauth(data, conn, mech, resp);
if(!result) {
*progress = SASL_INPROGRESS;
- state(sasl, data, resp ? state2 : state1);
+ state(sasl, data, Curl_bufref_ptr(&resp) ? state2 : state1);
}
}
- free(resp);
-
+ Curl_bufref_free(&resp);
return result;
}
@@ -464,29 +508,25 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
{
CURLcode result = CURLE_OK;
saslstate newstate = SASL_FINAL;
- char *resp = NULL;
+ struct bufref resp;
#ifndef CURL_DISABLE_PROXY
- const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
- conn->host.name;
+ const char * const hostname = SSL_HOST_NAME();
const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
#else
const char * const hostname = conn->host.name;
const long int port = conn->remote_port;
#endif
-#if !defined(CURL_DISABLE_CRYPTO_AUTH)
- char *chlg = NULL;
- size_t chlglen = 0;
-#endif
#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) || \
defined(USE_NTLM)
const char *service = data->set.str[STRING_SERVICE_NAME] ?
data->set.str[STRING_SERVICE_NAME] :
sasl->params->service;
- char *serverdata;
#endif
- size_t len = 0;
const char *oauth_bearer = data->set.str[STRING_BEARER];
+ struct bufref serverdata;
+ Curl_bufref_init(&serverdata);
+ Curl_bufref_init(&resp);
*progress = SASL_INPROGRESS;
if(sasl->state == SASL_FINAL) {
@@ -509,50 +549,45 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
*progress = SASL_DONE;
return result;
case SASL_PLAIN:
- result = Curl_auth_create_plain_message(data, conn->sasl_authzid,
- conn->user, conn->passwd,
- &resp, &len);
+ result = Curl_auth_create_plain_message(conn->sasl_authzid,
+ conn->user, conn->passwd, &resp);
break;
case SASL_LOGIN:
- result = Curl_auth_create_login_message(data, conn->user, &resp, &len);
+ result = Curl_auth_create_login_message(conn->user, &resp);
newstate = SASL_LOGIN_PASSWD;
break;
case SASL_LOGIN_PASSWD:
- result = Curl_auth_create_login_message(data, conn->passwd, &resp, &len);
+ result = Curl_auth_create_login_message(conn->passwd, &resp);
break;
case SASL_EXTERNAL:
- result = Curl_auth_create_external_message(data, conn->user, &resp, &len);
+ result = Curl_auth_create_external_message(conn->user, &resp);
break;
#ifndef CURL_DISABLE_CRYPTO_AUTH
#ifdef USE_GSASL
case SASL_GSASL:
- sasl->params->getmessage(data->state.buffer, &serverdata);
- result = Curl_auth_gsasl_token(data, serverdata, &conn->gsasl,
- &resp, &len);
- if(len > 0)
+ result = get_server_message(sasl, data, &serverdata);
+ if(!result)
+ result = Curl_auth_gsasl_token(data, &serverdata, &conn->gsasl, &resp);
+ if(!result && Curl_bufref_len(&resp) > 0)
newstate = SASL_GSASL;
break;
#endif
case SASL_CRAMMD5:
- sasl->params->getmessage(data->state.buffer, &serverdata);
- result = Curl_auth_decode_cram_md5_message(serverdata, &chlg, &chlglen);
+ result = get_server_message(sasl, data, &serverdata);
if(!result)
- result = Curl_auth_create_cram_md5_message(data, chlg, conn->user,
- conn->passwd, &resp, &len);
- free(chlg);
+ result = Curl_auth_create_cram_md5_message(&serverdata, conn->user,
+ conn->passwd, &resp);
break;
case SASL_DIGESTMD5:
- sasl->params->getmessage(data->state.buffer, &serverdata);
- result = Curl_auth_create_digest_md5_message(data, serverdata,
- conn->user, conn->passwd,
- service,
- &resp, &len);
+ result = get_server_message(sasl, data, &serverdata);
+ if(!result)
+ result = Curl_auth_create_digest_md5_message(data, &serverdata,
+ conn->user, conn->passwd,
+ service, &resp);
newstate = SASL_DIGESTMD5_RESP;
break;
case SASL_DIGESTMD5_RESP:
- resp = strdup("");
- if(!resp)
- result = CURLE_OUT_OF_MEMORY;
+ /* Keep response NULL to output an empty line. */
break;
#endif
@@ -562,18 +597,19 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
result = Curl_auth_create_ntlm_type1_message(data,
conn->user, conn->passwd,
service, hostname,
- &conn->ntlm, &resp, &len);
+ &conn->ntlm, &resp);
newstate = SASL_NTLM_TYPE2MSG;
break;
case SASL_NTLM_TYPE2MSG:
/* Decode the type-2 message */
- sasl->params->getmessage(data->state.buffer, &serverdata);
- result = Curl_auth_decode_ntlm_type2_message(data, serverdata,
- &conn->ntlm);
+ result = get_server_message(sasl, data, &serverdata);
+ if(!result)
+ result = Curl_auth_decode_ntlm_type2_message(data, &serverdata,
+ &conn->ntlm);
if(!result)
result = Curl_auth_create_ntlm_type3_message(data, conn->user,
conn->passwd, &conn->ntlm,
- &resp, &len);
+ &resp);
break;
#endif
@@ -582,55 +618,59 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
result = Curl_auth_create_gssapi_user_message(data, conn->user,
conn->passwd,
service,
- data->conn->host.name,
+ conn->host.name,
sasl->mutual_auth, NULL,
&conn->krb5,
- &resp, &len);
+ &resp);
newstate = SASL_GSSAPI_TOKEN;
break;
case SASL_GSSAPI_TOKEN:
- sasl->params->getmessage(data->state.buffer, &serverdata);
- if(sasl->mutual_auth) {
- /* Decode the user token challenge and create the optional response
- message */
- result = Curl_auth_create_gssapi_user_message(data, NULL, NULL,
- NULL, NULL,
- sasl->mutual_auth,
- serverdata, &conn->krb5,
- &resp, &len);
- newstate = SASL_GSSAPI_NO_DATA;
+ result = get_server_message(sasl, data, &serverdata);
+ if(!result) {
+ if(sasl->mutual_auth) {
+ /* Decode the user token challenge and create the optional response
+ message */
+ result = Curl_auth_create_gssapi_user_message(data, NULL, NULL,
+ NULL, NULL,
+ sasl->mutual_auth,
+ &serverdata,
+ &conn->krb5,
+ &resp);
+ newstate = SASL_GSSAPI_NO_DATA;
+ }
+ else
+ /* Decode the security challenge and create the response message */
+ result = Curl_auth_create_gssapi_security_message(data, &serverdata,
+ &conn->krb5,
+ &resp);
}
- else
- /* Decode the security challenge and create the response message */
- result = Curl_auth_create_gssapi_security_message(data, serverdata,
- &conn->krb5,
- &resp, &len);
break;
case SASL_GSSAPI_NO_DATA:
- sasl->params->getmessage(data->state.buffer, &serverdata);
/* Decode the security challenge and create the response message */
- result = Curl_auth_create_gssapi_security_message(data, serverdata,
- &conn->krb5,
- &resp, &len);
+ result = get_server_message(sasl, data, &serverdata);
+ if(!result)
+ result = Curl_auth_create_gssapi_security_message(data, &serverdata,
+ &conn->krb5,
+ &resp);
break;
#endif
case SASL_OAUTH2:
/* Create the authorisation message */
if(sasl->authused == SASL_MECH_OAUTHBEARER) {
- result = Curl_auth_create_oauth_bearer_message(data, conn->user,
+ result = Curl_auth_create_oauth_bearer_message(conn->user,
hostname,
port,
oauth_bearer,
- &resp, &len);
+ &resp);
/* Failures maybe sent by the server as continuations for OAUTHBEARER */
newstate = SASL_OAUTH2_RESP;
}
else
- result = Curl_auth_create_xoauth_bearer_message(data, conn->user,
+ result = Curl_auth_create_xoauth_bearer_message(conn->user,
oauth_bearer,
- &resp, &len);
+ &resp);
break;
case SASL_OAUTH2_RESP:
@@ -642,11 +682,8 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
return result;
}
else if(code == sasl->params->contcode) {
- /* Acknowledge the continuation by sending a 0x01 response base64
- encoded */
- resp = strdup("AQ==");
- if(!resp)
- result = CURLE_OUT_OF_MEMORY;
+ /* Acknowledge the continuation by sending a 0x01 response. */
+ Curl_bufref_set(&resp, "\x01", 1, NULL);
break;
}
else {
@@ -660,15 +697,15 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
sasl->authmechs ^= sasl->authused;
/* Start an alternative SASL authentication */
- result = Curl_sasl_start(sasl, data, conn, sasl->force_ir, progress);
- newstate = sasl->state; /* Use state from Curl_sasl_start() */
- break;
+ return Curl_sasl_start(sasl, data, conn, sasl->force_ir, progress);
default:
failf(data, "Unsupported SASL authentication mechanism");
result = CURLE_UNSUPPORTED_PROTOCOL; /* Should not happen */
break;
}
+ Curl_bufref_free(&serverdata);
+
switch(result) {
case CURLE_BAD_CONTENT_ENCODING:
/* Cancel dialog */
@@ -676,8 +713,10 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
newstate = SASL_CANCEL;
break;
case CURLE_OK:
- if(resp)
- result = sasl->params->sendcont(data, conn, resp);
+ result = build_message(data, &resp);
+ if(!result)
+ result = sasl->params->sendcont(data, conn,
+ (const char *) Curl_bufref_ptr(&resp));
break;
default:
newstate = SASL_STOP; /* Stop on error */
@@ -685,7 +724,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
break;
}
- free(resp);
+ Curl_bufref_free(&resp);
state(sasl, data, newstate);