summaryrefslogtreecommitdiffstats
path: root/proxy/src/gp_export.c
diff options
context:
space:
mode:
authorSimo Sorce <simo@redhat.com>2016-11-30 09:06:33 -0500
committerSimo Sorce <simo@redhat.com>2017-01-13 15:50:06 -0500
commit2d49ba029e5b0fdaa4bafc3d5bca0cb1169c9877 (patch)
tree0eda5a7654de058300d3cbf642b60c3819c4e141 /proxy/src/gp_export.c
parent56d2a3119c4713fbfabf98b0afc0882d64324166 (diff)
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@redhat.com>
Diffstat (limited to 'proxy/src/gp_export.c')
-rw-r--r--proxy/src/gp_export.c120
1 files changed, 108 insertions, 12 deletions
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) {