summaryrefslogtreecommitdiff
path: root/imap/src/c-client/oauth2_aux.c
diff options
context:
space:
mode:
authorEduardo Chappa <chappa@washington.edu>2021-11-21 02:19:32 -0700
committerEduardo Chappa <chappa@washington.edu>2021-11-21 02:19:32 -0700
commit7d652142f4960b679cb5399fc0485470af2cc878 (patch)
tree7afa6235429b5fdb835586bf671fa532b37281c3 /imap/src/c-client/oauth2_aux.c
parent626eccdd8d0a325842d736596348e9d1d81ca105 (diff)
downloadalpine-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.c140
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);
}