This is an automated email from the git hooks/post-receive script.
rharwood pushed a commit to branch master
in repository gssproxy.
commit 1e6b5a4c004c520c5865c04c6bd3d40373d174c2
Author: Simo Sorce <simo(a)redhat.com>
Date: Wed Nov 30 09:06:33 2016 -0500
Use a local keytab for creds encryption
If available use a keytab for creds encryption.
Since now we can store encrypted credentials, on the cient side, for later
reuse, it is better to be able to decrypt them even after a gssproxy daemon
restart (maintenance, crashes, etc..)
If a keytab is rotated this can cause a restarted gssproxy to fail to decrypt
stored credentials, but in that case those credentials are also probably
useless and need to be refreshed, so this is not a huge deal, and definitely
better than the status quo.
Signed-off-by: Simo Sorce <simo(a)redhat.com>
Reviewed-by: Robbie Harwood <rharwood(a)redhat.com>
---
proxy/src/gp_config.c | 47 ++++++++++++--------
proxy/src/gp_export.c | 120 +++++++++++++++++++++++++++++++++++++++++++++-----
proxy/src/gp_proxy.h | 11 ++---
3 files changed, 142 insertions(+), 36 deletions(-)
diff --git a/proxy/src/gp_config.c b/proxy/src/gp_config.c
index 2e14072..72b587d 100644
--- a/proxy/src/gp_config.c
+++ b/proxy/src/gp_config.c
@@ -62,12 +62,33 @@ static void gp_service_free(struct gp_service *svc)
free(svc->krb5.principal);
free_str_array(&(svc->krb5.cred_store),
&svc->krb5.cred_count);
+ gp_free_creds_handle(&svc->krb5.creds_handle);
}
- gp_free_creds_handle(&svc->creds_handle);
SELINUX_context_free(svc->selinux_ctx);
memset(svc, 0, sizeof(struct gp_service));
}
+static int setup_krb5_creds_handle(struct gp_service *svc)
+{
+ uint32_t ret_maj, ret_min;
+ const char *keytab = NULL;
+
+ for (unsigned i = 0; i < svc->krb5.cred_count; i++) {
+ if (strncmp(svc->krb5.cred_store[i], "keytab:", 7) == 0) {
+ keytab = svc->krb5.cred_store[i] + 7;
+ break;
+ }
+ }
+
+ ret_maj = gp_init_creds_handle(&ret_min, svc->name, keytab,
+ &svc->krb5.creds_handle);
+ if (ret_maj) {
+ return ret_min;
+ }
+
+ return 0;
+}
+
static int get_krb5_mech_cfg(struct gp_service *svc,
struct gp_ini_context *ctx,
const char *secname)
@@ -115,6 +136,10 @@ static int get_krb5_mech_cfg(struct gp_service *svc,
ret = 0;
}
+ if (ret == 0) {
+ ret = setup_krb5_creds_handle(svc);
+ }
+
return ret;
}
@@ -171,18 +196,6 @@ static int parse_flags(const char *value, uint32_t *storage)
return 0;
}
-static int setup_service_creds_handle(struct gp_service *svc)
-{
- uint32_t ret_maj, ret_min;
-
- ret_maj = gp_init_creds_handle(&ret_min, &svc->creds_handle);
- if (ret_maj) {
- return ret_min;
- }
-
- return 0;
-}
-
static int check_services(const struct gp_config *cfg)
{
int i, j;
@@ -339,11 +352,6 @@ static int load_services(struct gp_config *cfg, struct gp_ini_context
*ctx)
}
}
- ret = setup_service_creds_handle(cfg->svcs[n]);
- if (ret) {
- goto done;
- }
-
ret = gp_config_get_string(ctx, secname, "mechs", &value);
if (ret != 0) {
/* if mechs is missing or there is an error retrieving it
@@ -377,6 +385,7 @@ static int load_services(struct gp_config *cfg, struct gp_ini_context
*ctx)
safefree(vcopy);
return ret;
}
+
} else {
GPERROR("Unknown mech: %s in [%s], ignoring.\n",
token, secname);
@@ -604,7 +613,7 @@ done:
struct gp_creds_handle *gp_service_get_creds_handle(struct gp_service *svc)
{
- return svc->creds_handle;
+ return svc->krb5.creds_handle;
}
void free_config(struct gp_config **cfg)
diff --git a/proxy/src/gp_export.c b/proxy/src/gp_export.c
index 41af67b..c83303a 100644
--- a/proxy/src/gp_export.c
+++ b/proxy/src/gp_export.c
@@ -17,8 +17,8 @@
#define GP_CREDS_HANDLE_KEY_ENCTYPE ENCTYPE_AES256_CTS_HMAC_SHA1_96
struct gp_creds_handle {
- krb5_keyblock key;
krb5_context context;
+ krb5_keyblock *key;
};
void gp_free_creds_handle(struct gp_creds_handle **in)
@@ -30,7 +30,7 @@ void gp_free_creds_handle(struct gp_creds_handle **in)
}
if (handle->context) {
- krb5_free_keyblock_contents(handle->context, &handle->key);
+ krb5_free_keyblock(handle->context, handle->key);
krb5_free_context(handle->context);
}
@@ -39,11 +39,15 @@ void gp_free_creds_handle(struct gp_creds_handle **in)
return;
}
-uint32_t gp_init_creds_handle(uint32_t *min, struct gp_creds_handle **out)
+uint32_t gp_init_creds_handle(uint32_t *min, const char *svc_name,
+ const char *keytab,
+ struct gp_creds_handle **out)
{
struct gp_creds_handle *handle;
uint32_t ret_maj = 0;
uint32_t ret_min = 0;
+ krb5_keytab ktid = NULL;
+ char ktname[MAX_KEYTAB_NAME_LEN + 1] = {0};
int ret;
handle = calloc(1, sizeof(struct gp_creds_handle));
@@ -61,19 +65,111 @@ uint32_t gp_init_creds_handle(uint32_t *min, struct gp_creds_handle
**out)
goto done;
}
- ret = krb5_c_make_random_key(handle->context,
- GP_CREDS_HANDLE_KEY_ENCTYPE,
+ /* Try to use a keytab, and fall back to a random runtime secret if all
+ * else fails */
+ if (keytab) {
+ ret = krb5_kt_resolve(handle->context, keytab, &ktid);
+ if (ret == 0) {
+ ret = krb5_kt_have_content(handle->context, ktid);
+ }
+ /* if a keytab is specified then it must be usable */
+ if (ret) {
+ ret_min = ret;
+ ret_maj = GSS_S_CRED_UNAVAIL;
+ goto done;
+ }
+ strncpy(ktname, keytab, MAX_KEYTAB_NAME_LEN);
+ } else {
+ ret = krb5_kt_default(handle->context, &ktid);
+ /* if the default keyab does not exist or is empty it is not fatal */
+ if (ret) {
+ ktid = NULL;
+ } else {
+ ret = krb5_kt_have_content(handle->context, ktid);
+ if (ret) {
+ (void)krb5_kt_close(handle->context, ktid);
+ ktid = NULL;
+ } else {
+ ret = krb5_kt_default_name(handle->context, ktname,
+ MAX_KEYTAB_NAME_LEN);
+ if (ret) strncpy(ktname, "[default]", MAX_KEYTAB_NAME_LEN);
+ }
+ }
+ }
+
+ if (ktid) {
+ krb5_kt_cursor cursor;
+ krb5_keytab_entry entry;
+ krb5_enctype *permitted;
+
+ ret = krb5_get_permitted_enctypes(handle->context, &permitted);
+ if (ret) {
+ ret_min = ret;
+ ret_maj = GSS_S_FAILURE;
+ goto done;
+ }
+
+ ret = krb5_kt_start_seq_get(handle->context, ktid, &cursor);
+ if (ret) {
+ ret_min = ret;
+ ret_maj = GSS_S_FAILURE;
+ goto done;
+ }
+ do {
+ ret = krb5_kt_next_entry(handle->context, ktid, &entry, &cursor);
+ if (ret == 0) {
+ for (unsigned i = 0; permitted[i] != 0; i++) {
+ if (permitted[i] == entry.key.enctype) {
+ /* should we derive a key instead ? */
+ ret = krb5_copy_keyblock(handle->context, &entry.key,
+ &handle->key);
+ if (ret == 0) {
+ GPDEBUG("Service: %s, Enckey: %s, Enctype: %d\n",
+ svc_name, ktname, entry.key.enctype);
+ ret = KRB5_KT_END;
+ }
+ break;
+ }
+ }
+ (void)krb5_free_keytab_entry_contents(handle->context, &entry);
+ }
+ } while (ret == 0);
+ (void)krb5_kt_end_seq_get(handle->context, ktid, &cursor);
+ if ((ret == KRB5_KT_END) && (handle->key == NULL)) {
+ ret = KRB5_WRONG_ETYPE;
+ ret_maj = GSS_S_CRED_UNAVAIL;
+ goto done;
+ }
+ if (ret != KRB5_KT_END) {
+ ret_min = ret;
+ ret_maj = GSS_S_CRED_UNAVAIL;
+ goto done;
+ }
+ } else {
+ ret = krb5_init_keyblock(handle->context,
+ GP_CREDS_HANDLE_KEY_ENCTYPE, 0,
&handle->key);
- if (ret) {
- ret_min = ret;
- ret_maj = GSS_S_FAILURE;
- goto done;
+ if (ret == 0) {
+ ret = krb5_c_make_random_key(handle->context,
+ GP_CREDS_HANDLE_KEY_ENCTYPE,
+ handle->key);
+ GPDEBUG("Service: %s, Enckey: [ephemeral], Enctype: %d\n",
+ svc_name, GP_CREDS_HANDLE_KEY_ENCTYPE);
+ }
+ if (ret) {
+ ret_min = ret;
+ ret_maj = GSS_S_FAILURE;
+ goto done;
+ }
}
ret_maj = GSS_S_COMPLETE;
ret_min = 0;
done:
+ if (handle->context && ktid) {
+ (void)krb5_kt_close(handle->context, ktid);
+ }
*min = ret_min;
if (ret_maj) {
gp_free_creds_handle(&handle);
@@ -97,7 +193,7 @@ static int gp_encrypt_buffer(krb5_context context, krb5_keyblock *key,
memset(&enc_handle, '\0', sizeof(krb5_enc_data));
ret = krb5_c_encrypt_length(context,
- GP_CREDS_HANDLE_KEY_ENCTYPE,
+ key->enctype,
data_in.length,
&cipherlen);
if (ret) {
@@ -254,7 +350,7 @@ uint32_t gp_export_gssx_cred(uint32_t *min, struct gp_call_ctx
*gpcall,
goto done;
}
- ret = gp_encrypt_buffer(handle->context, &handle->key,
+ ret = gp_encrypt_buffer(handle->context, handle->key,
token.length, token.value,
&out->cred_handle_reference);
if (ret) {
@@ -338,7 +434,7 @@ uint32_t gp_import_gssx_cred(uint32_t *min, struct gp_call_ctx
*gpcall,
goto done;
}
- ret = gp_decrypt_buffer(handle->context, &handle->key,
+ ret = gp_decrypt_buffer(handle->context, handle->key,
&cred->cred_handle_reference,
&token.length, token.value);
if (ret) {
diff --git a/proxy/src/gp_proxy.h b/proxy/src/gp_proxy.h
index be71d38..c7f4bb2 100644
--- a/proxy/src/gp_proxy.h
+++ b/proxy/src/gp_proxy.h
@@ -17,14 +17,15 @@
#define GP_CRED_KRB5 0x01
+struct gp_creds_handle;
+
struct gp_cred_krb5 {
char *principal;
const char **cred_store;
int cred_count;
+ struct gp_creds_handle *creds_handle;
};
-struct gp_creds_handle;
-
struct gp_service {
char *name;
uid_t euid;
@@ -41,8 +42,6 @@ struct gp_service {
uint32_t mechs;
struct gp_cred_krb5 krb5;
- struct gp_creds_handle *creds_handle;
-
verto_ev *ev;
};
@@ -127,7 +126,9 @@ struct gp_service *gp_creds_match_conn(struct gssproxy_ctx *gpctx,
struct gp_conn *conn);
/* from gp_export.c */
-uint32_t gp_init_creds_handle(uint32_t *min, struct gp_creds_handle **out);
+uint32_t gp_init_creds_handle(uint32_t *min, const char *svc_name,
+ const char *keytab,
+ struct gp_creds_handle **out);
void gp_free_creds_handle(struct gp_creds_handle **in);
#endif /* _GP_PROXY_H_ */
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.