From c4aa3d46e334461988acf17596fd34a6baa82aa3 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Sat, 13 Jun 2015 16:46:40 -0400 Subject: [PATCH] Optimize BASIC AUTH checks with sessions. If sessions are enbled store a MAC of the password and use it to check if the password is the same on follow-up requests. If it is, avoid the whole gssapi dance and use the session data instead. Signed-off-by: Simo Sorce --- src/crypto.c | 9 +++++++++ src/crypto.h | 1 + src/mod_auth_gssapi.c | 21 ++++++++++++++------ src/mod_auth_gssapi.h | 1 + src/sessions.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/sessions.h | 4 ++++ 6 files changed, 85 insertions(+), 6 deletions(-) diff --git a/src/crypto.c b/src/crypto.c index 54cb0c7..07c078c 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -233,3 +233,12 @@ done: EVP_CIPHER_CTX_cleanup(&ctx); return err; } + +int get_mac_size(struct seal_key *skey) +{ + if (skey) { + return skey->md->md_size; + } else { + return 0; + } +} diff --git a/src/crypto.h b/src/crypto.h index 40cfc31..9c87ca5 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -18,3 +18,4 @@ apr_status_t SEAL_BUFFER(apr_pool_t *p, struct seal_key *skey, struct databuf *plain, struct databuf *cipher); apr_status_t UNSEAL_BUFFER(apr_pool_t *p, struct seal_key *skey, struct databuf *cipher, struct databuf *plain); +int get_mac_size(struct seal_key *skey); diff --git a/src/mod_auth_gssapi.c b/src/mod_auth_gssapi.c index 79d62cd..8687568 100644 --- a/src/mod_auth_gssapi.c +++ b/src/mod_auth_gssapi.c @@ -422,8 +422,12 @@ static int mag_auth(request_rec *req) mag_set_KRB5CCANME(req, ccname); } } - ret = OK; - goto done; + if (mc->auth_type != AUTH_TYPE_BASIC) { + /* In case we have basic auth, we need to check if the session + * matches the credentials that have been sent */ + ret = OK; + goto done; + } } pctx = &mc->ctx; } else { @@ -467,6 +471,12 @@ static int mag_auth(request_rec *req) } ba_user.length = strlen(ba_user.value); ba_pwd.length = strlen(ba_pwd.value); + + if (mc && mag_basic_check(cfg, mc, ba_user, ba_pwd)) { + ret = OK; + goto done; + } + maj = gss_import_name(&min, &ba_user, GSS_C_NT_USER_NAME, &client); if (GSS_ERROR(maj)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, @@ -609,10 +619,6 @@ static int mag_auth(request_rec *req) goto done; } if (auth_type == AUTH_TYPE_BASIC) { - if (mc) { - apr_pool_cleanup_run(mc->parent, mc, mag_conn_destroy); - mc = NULL; - } while (maj == GSS_S_CONTINUE_NEEDED) { gss_release_buffer(&min, &input); /* output and input are inverted here, this is intentional */ @@ -707,6 +713,9 @@ static int mag_auth(request_rec *req) mag_attempt_session(req, cfg, mc); } mc->auth_type = auth_type; + if (auth_type == AUTH_TYPE_BASIC) { + mag_basic_cache(cfg, mc, ba_user, ba_pwd); + } } if (cfg->send_persist) diff --git a/src/mod_auth_gssapi.h b/src/mod_auth_gssapi.h index 97ba2c8..00765c4 100644 --- a/src/mod_auth_gssapi.h +++ b/src/mod_auth_gssapi.h @@ -68,6 +68,7 @@ struct mag_conn { time_t expiration; int auth_type; bool delegated; + struct databuf basic_hash; }; #define discard_const(ptr) ((void *)((uintptr_t)(ptr))) diff --git a/src/sessions.c b/src/sessions.c index f90857c..2653ccd 100644 --- a/src/sessions.c +++ b/src/sessions.c @@ -255,3 +255,58 @@ done: ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_GSSSessionData, &gsessdata); } +static int mag_basic_hmac(struct seal_key *key, unsigned char *mac, + gss_buffer_desc user, gss_buffer_desc pwd) +{ + struct databuf hmacbuf = { mac, 0 }; + int data_size = user.length + pwd.length + 1; + unsigned char data[data_size]; + struct databuf databuf = { data, data_size }; + + memcpy(data, user.value, user.length); + data[user.length] = '\0'; + memcpy(&data[user.length + 1], pwd.value, pwd.length); + + return HMAC_BUFFER(key, &databuf, &hmacbuf); +} + +bool mag_basic_check(struct mag_config *cfg, struct mag_conn *mc, + gss_buffer_desc user, gss_buffer_desc pwd) +{ + int mac_size = get_mac_size(cfg->mag_skey); + unsigned char mac[mac_size]; + int ret, i, j; + bool res = false; + + if (mac_size == 0) return false; + + ret = mag_basic_hmac(cfg->mag_skey, mac, user, pwd); + if (ret != 0) goto done; + + for (i = 0, j = 0; i < mac_size; i++) { + if (mc->basic_hash.value[i] != mac[i]) j++; + } + if (j == 0) res = true; + +done: + if (res == false) { + mc->basic_hash.value = NULL; + mc->basic_hash.length = 0; + } + return res; +} + +void mag_basic_cache(struct mag_config *cfg, struct mag_conn *mc, + gss_buffer_desc user, gss_buffer_desc pwd) +{ + int mac_size = get_mac_size(cfg->mag_skey); + unsigned char mac[mac_size]; + int ret; + + ret = mag_basic_hmac(cfg->mag_skey, mac, user, pwd); + if (ret != 0) return; + + mc->basic_hash.length = mac_size; + mc->basic_hash.value = apr_palloc(mc->parent, mac_size); + memcpy(mc->basic_hash.value, mac, mac_size); +} diff --git a/src/sessions.h b/src/sessions.h index f3b398e..840dbe9 100644 --- a/src/sessions.h +++ b/src/sessions.h @@ -8,3 +8,7 @@ void mag_check_session(request_rec *req, struct mag_config *cfg, struct mag_conn **conn); void mag_attempt_session(request_rec *req, struct mag_config *cfg, struct mag_conn *mc); +bool mag_basic_check(struct mag_config *cfg, struct mag_conn *mc, + gss_buffer_desc user, gss_buffer_desc pwd); +void mag_basic_cache(struct mag_config *cfg, struct mag_conn *mc, + gss_buffer_desc user, gss_buffer_desc pwd); -- 2.1.4