diff options
author | Eduardo Chappa <chappa@washington.edu> | 2021-11-21 02:19:32 -0700 |
---|---|---|
committer | Eduardo Chappa <chappa@washington.edu> | 2021-11-21 02:19:32 -0700 |
commit | 7d652142f4960b679cb5399fc0485470af2cc878 (patch) | |
tree | 7afa6235429b5fdb835586bf671fa532b37281c3 /imap/src/c-client/oauth2_aux.c | |
parent | 626eccdd8d0a325842d736596348e9d1d81ca105 (diff) | |
download | alpine-7d652142f4960b679cb5399fc0485470af2cc878.tar.xz |
* Support for code_verifier and code_challenge when generating a
refresh token and access token in Gmail using the S256 method
and plain method.
Diffstat (limited to 'imap/src/c-client/oauth2_aux.c')
-rw-r--r-- | imap/src/c-client/oauth2_aux.c | 140 |
1 files changed, 120 insertions, 20 deletions
diff --git a/imap/src/c-client/oauth2_aux.c b/imap/src/c-client/oauth2_aux.c index 363f41d1..eac92a10 100644 --- a/imap/src/c-client/oauth2_aux.c +++ b/imap/src/c-client/oauth2_aux.c @@ -24,6 +24,125 @@ #include "json.h" #include "oauth2_aux.h" +OA2_type oauth2_find_extra_parameter(OAUTH2_S *, char *); +JSON_S *oauth2_json_reply(OAUTH2_SERVER_METHOD_S, OAUTH2_S *, int *); +char *xoauth2_server(char *, char *); + +#define LOAD_HTTP_PARAMS(X, Y) { \ + int i; \ + for(i = 0; (X).params[i] != OA2_End; i++){ \ + OA2_type j = (X).params[i]; \ + (Y)[i].name = oauth2->param[j].name; \ + (Y)[i].value = oauth2->param[j].value; \ + } \ + (Y)[i].name = (Y)[i].value = NULL; \ +} + +#define OAUTH2_CLEAR_EXTRA(X, Y) do { \ + OA2_type i = oauth2_find_extra_parameter(&(X), (Y)); \ + if(i < OA2_End && (X).param[i].value) \ + fs_give((void **) &(X).param[i].value); \ +} while(0) + +void oauth2_free_extra_values(OAUTH2_S oauth2) +{ + OA2_type i; + + if(oauth2.param[OA2_Id].value) fs_give((void **) &oauth2.param[OA2_Id].value); + if(oauth2.param[OA2_Secret].value) fs_give((void **) &oauth2.param[OA2_Secret].value); + if(oauth2.param[OA2_Tenant].value) fs_give((void **) &oauth2.param[OA2_Tenant].value); + if(oauth2.param[OA2_State].value) fs_give((void **) &oauth2.param[OA2_State].value); + if(oauth2.param[OA2_RefreshToken].value) fs_give((void **) &oauth2.param[OA2_RefreshToken].value); + if(oauth2.access_token) fs_give((void **) &oauth2.access_token); + + /* free extra parameters generated by us */ + OAUTH2_CLEAR_EXTRA(oauth2, "code_verifier"); + OAUTH2_CLEAR_EXTRA(oauth2, "code_challenge"); + OAUTH2_CLEAR_EXTRA(oauth2, "login_hint"); +} + +OA2_type oauth2_find_extra_parameter(OAUTH2_S *oauth2, char *name) +{ + OA2_type i; + + if(!name) return OA2_End; + + for(i = OA2_Extra1; i < OA2_End; i++){ + if(oauth2->param[i].name + && !compare_cstring(oauth2->param[i].name, name)) + break; + } + return i; +} + +/* code_challenge generator */ +void oauth2_code_challenge(OAUTH2_S *oauth2) +{ + OA2_type i, j, k; + char *cv, *cv1, *cv2; + + i = oauth2_find_extra_parameter(oauth2, "code_verifier"); + + if(i == OA2_End) return; + + j = oauth2_find_extra_parameter(oauth2, "code_challenge"); + + if(j == OA2_End) return; + + k = oauth2_find_extra_parameter(oauth2, "code_challenge_method"); + + cv1 = oauth2_generate_state(); + cv2 = oauth2_generate_state(); + + if(!cv1 || !cv2) return; + + if(oauth2->param[i].value) fs_give((void **) &oauth2->param[i].value); + if(oauth2->param[j].value) fs_give((void **) &oauth2->param[j].value); + + cv = fs_get(strlen(cv1) + strlen(cv2) + 1 + 1); + if(cv){ + sprintf(cv, "%s-%s", cv1, cv2); + fs_give((void **) &cv1); + fs_give((void **) &cv2); + oauth2->param[i].value = cv; + if(k == OA2_End + || !compare_cstring(oauth2->param[k].value, "plain")) + oauth2->param[j].value = cpystr(cv); + else if(!compare_cstring(oauth2->param[k].value, "S256")){ + unsigned char *t, *u, *v; + char *s = hash_from_sizedtext("SHA256", cv, strlen(cv), &t); + if(s){ + u = v = t; + if(t){ + for(; *v != '\0'; v++){ + if(*v < 0x20) continue; + *u++ = *v; + } + *u = '\0'; + oauth2->param[j].value = t; + } + fs_give((void **) &s); + } + } + } +} + +/* code_challenge generator */ +void oauth2_login_hint(OAUTH2_S *oauth2, char *user) +{ + OA2_type i, j, k; + char *cv, *cv1, *cv2; + + if(!user || !*user) return; + + i = oauth2_find_extra_parameter(oauth2, "login_hint"); + + if(i == OA2_End) return; + + if(oauth2->param[i].value) fs_give((void **) &oauth2->param[i].value); + oauth2->param[i].value = cpystr(user); +} + /* we generate something like a guid, but not care about * anything, but that it is really random. */ @@ -51,20 +170,6 @@ char *oauth2_generate_state(void) return cpystr(rv); } - -JSON_S *oauth2_json_reply(OAUTH2_SERVER_METHOD_S, OAUTH2_S *, int *); -char *xoauth2_server(char *, char *); - -#define LOAD_HTTP_PARAMS(X, Y) { \ - int i; \ - for(i = 0; (X).params[i] != OA2_End; i++){ \ - OA2_type j = (X).params[i]; \ - (Y)[i].name = oauth2->param[j].name; \ - (Y)[i].value = oauth2->param[j].value; \ - } \ - (Y)[i].name = (Y)[i].value = NULL; \ -} - char * xoauth2_server(char *server, char *tenant) { @@ -483,10 +588,5 @@ void renew_accesstoken(MAILSTREAM *stream) mm_login_method (&mb, user, (void *) &oauth2, trial, stream->auth.name); stream->auth.expiration = oauth2.expiration; - if(oauth2.param[OA2_Id].value) fs_give((void **) &oauth2.param[OA2_Id].value); - if(oauth2.param[OA2_Secret].value) fs_give((void **) &oauth2.param[OA2_Secret].value); - if(oauth2.param[OA2_Tenant].value) fs_give((void **) &oauth2.param[OA2_Tenant].value); - if(oauth2.param[OA2_State].value) fs_give((void **) &oauth2.param[OA2_State].value); - if(oauth2.param[OA2_RefreshToken].value) fs_give((void **) &oauth2.param[OA2_RefreshToken].value); - if(oauth2.access_token) fs_give((void **) &oauth2.access_token); + oauth2_free_extra_values(oauth2); } |