aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Hartman <hartmans@mit.edu>2009-03-26 05:37:06 +0000
committerSam Hartman <hartmans@mit.edu>2009-03-26 05:37:06 +0000
commit10609fbcf5d3a056a74633224401904ad88818b7 (patch)
treed2a38809f25280b5e79dd3ff790e7d6f229227a1
parentfa2fcf03de2c39b0906bd33e31d445a5545755a3 (diff)
downloadkrb5-10609fbcf5d3a056a74633224401904ad88818b7.zip
krb5-10609fbcf5d3a056a74633224401904ad88818b7.tar.gz
krb5-10609fbcf5d3a056a74633224401904ad88818b7.tar.bz2
Implement client AS armor
* fast_armor_ap_request: generate ap_request armor * krb5int_fast_as_armor: parse GIC options and request armor * krb5_get_init_creds: call * krb5_get_init_creds_opt_set_fast_ccache_name: API to indicate where armor credentials are found * krb5_free_fast_armored_req: implement git-svn-id: svn://anonsvn.mit.edu/krb5/branches/fast@22134 dc483132-0cff-0310-8789-dd5450dbe970
-rw-r--r--src/include/k5-int.h5
-rw-r--r--src/include/krb5/krb5.hin9
-rw-r--r--src/lib/krb5/krb/fast.c120
-rw-r--r--src/lib/krb5/krb/fast.h4
-rw-r--r--src/lib/krb5/krb/get_in_tkt.c3
-rw-r--r--src/lib/krb5/krb/gic_opt.c20
-rw-r--r--src/lib/krb5/krb/kfree.c14
-rw-r--r--src/lib/krb5/libkrb5.exports1
8 files changed, 170 insertions, 6 deletions
diff --git a/src/include/k5-int.h b/src/include/k5-int.h
index 957f39c..b7e793b 100644
--- a/src/include/k5-int.h
+++ b/src/include/k5-int.h
@@ -963,6 +963,10 @@ typedef struct _krb5_pa_for_user {
krb5_data auth_package;
} krb5_pa_for_user;
+enum {
+ KRB5_FAST_ARMOR_AP_REQUEST = 0x1
+};
+
typedef struct _krb5_fast_armor {
krb5_int32 armor_type;
krb5_data armor_value;
@@ -1130,6 +1134,7 @@ void krb5_free_etype_info
typedef struct _krb5_gic_opt_private {
int num_preauth_data;
krb5_gic_opt_pa_data *preauth_data;
+ char * fast_ccache_name;
} krb5_gic_opt_private;
/*
diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin
index c385387..4443d33 100644
--- a/src/include/krb5/krb5.hin
+++ b/src/include/krb5/krb5.hin
@@ -2410,6 +2410,15 @@ krb5_get_init_creds_opt_set_pa
const char *attr,
const char *value);
+krb5_error_code KRB5_CALLCONV krb5_get_init_creds_opt_set_fast_ccache_name
+(krb5_context context, krb5_get_init_creds_opt *opt,
+ const char * fast_ccache_name);
+ /* This API sets a ccache name that will contain some TGT on
+ calls to get_init_creds functions. If set, this ccache will
+ be used for FAST (draft-ietf-krb-wg-preauth-framework) to
+ protect the AS-REQ from observation and active attack. If
+ the fast_ccache_name is set, then FAST may be required by the
+ client library. In this version FAST is required.*/
krb5_error_code KRB5_CALLCONV
krb5_get_init_creds_password
(krb5_context context,
diff --git a/src/lib/krb5/krb/fast.c b/src/lib/krb5/krb/fast.c
index 41f3731..4d5f62e 100644
--- a/src/lib/krb5/krb/fast.c
+++ b/src/lib/krb5/krb/fast.c
@@ -49,8 +49,59 @@
* important questions there is the presence of a cookie.
*/
#include "fast.h"
+#include "int-proto.h"
+static krb5_error_code fast_armor_ap_request
+(krb5_context context, struct krb5int_fast_request_state *state,
+ krb5_ccache ccache, krb5_data *target_realm)
+{
+ krb5_error_code retval = 0;
+ krb5_creds creds, *out_creds = NULL;
+ krb5_auth_context authcontext = NULL;
+ krb5_data encoded_authenticator;
+ krb5_fast_armor *armor = NULL;
+ krb5_keyblock *subkey = NULL, *armor_key = NULL;
+ encoded_authenticator.data = NULL;
+ memset(&creds, 0, sizeof(creds));
+ retval = krb5_tgtname(context, target_realm, target_realm, &creds.server);
+ if (retval ==0)
+ retval = krb5_cc_get_principal(context, ccache, &creds.client);
+ if (retval == 0)
+ retval = krb5_get_credentials(context, 0, ccache, &creds, &out_creds);
+ if (retval == 0)
+ retval = krb5_mk_req_extended(context, &authcontext, AP_OPTS_USE_SUBKEY, NULL /*data*/,
+ out_creds, &encoded_authenticator);
+ if (retval == 0)
+ retval = krb5_auth_con_getsendsubkey(context, authcontext, &subkey);
+ if (retval == 0)
+ retval = krb5_c_fx_cf2_simple(context, subkey, "subkeyarmor",
+ &out_creds->keyblock, "ticketarmor", &armor_key);
+ if (retval == 0) {
+ armor = calloc(1, sizeof(krb5_fast_armor));
+ if (armor == NULL)
+ retval = ENOMEM;
+ }
+ if (retval == 0) {
+ armor->armor_type = KRB5_FAST_ARMOR_AP_REQUEST;
+ armor->armor_value = encoded_authenticator;
+ encoded_authenticator.data = NULL;
+ encoded_authenticator.length = 0;
+ state->armor = armor;
+ armor = NULL;
+ state->armor_key = armor_key;
+ armor_key = NULL;
+ }
+ krb5_free_keyblock(context, armor_key);
+ krb5_free_keyblock(context, subkey);
+ if (out_creds)
+ krb5_free_creds(context, out_creds);
+ krb5_free_cred_contents(context, &creds);
+ if (encoded_authenticator.data)
+ krb5_free_data_contents(context, &encoded_authenticator);
+ krb5_auth_con_free(context, authcontext);
+ return retval;
+}
krb5_error_code
krb5int_fast_prep_req_body(krb5_context context, struct krb5int_fast_request_state *state,
@@ -77,6 +128,34 @@ krb5int_fast_prep_req_body(krb5_context context, struct krb5int_fast_request_sta
return retval;
}
+krb5_error_code krb5int_fast_as_armor
+(krb5_context context, struct krb5int_fast_request_state *state,
+ krb5_gic_opt_ext *opte,
+ krb5_kdc_req *request)
+{
+ krb5_error_code retval = 0;
+ krb5_ccache ccache = NULL;
+ krb5_clear_error_message(context);
+ if (opte->opt_private->fast_ccache_name) {
+ retval = krb5_cc_resolve(context, opte->opt_private->fast_ccache_name,
+ &ccache);
+ if (retval==0)
+ retval = fast_armor_ap_request(context, state, ccache,
+ krb5_princ_realm(context, request->server));
+ if (retval != 0) {
+ const char * errmsg;
+ errmsg = krb5_get_error_message(context, retval);
+ if (errmsg) {
+ krb5_set_error_message(context, retval, "%s constructing AP-REQ armor", errmsg);
+ krb5_free_error_message(context, errmsg);
+ }
+ }
+ }
+ if (ccache)
+ krb5_cc_close(context, ccache);
+ return retval;
+}
+
krb5_error_code
krb5int_fast_prep_req (krb5_context context, struct krb5int_fast_request_state *state,
@@ -88,28 +167,51 @@ krb5int_fast_prep_req (krb5_context context, struct krb5int_fast_request_state *
krb5_pa_data *pa_array[3];
krb5_pa_data pa[2];
krb5_fast_req fast_req;
+ krb5_fast_armored_req *armored_req = NULL;
krb5_data *encoded_fast_req = NULL;
+ krb5_data *encoded_armored_req = NULL;
krb5_data *local_encoded_result = NULL;
+ krb5_cksumtype cksumtype;
assert(state != NULL);
- assert(state->fast_outer_request.padata == NULL);
+ assert(state->fast_outer_request.padata == NULL);
memset(pa_array, 0, sizeof pa_array);
if (state->armor_key == NULL) {
return encoder(request, encoded_request);
}
fast_req.req_body = request;
if (fast_req.req_body->padata == NULL) {
- fast_req.req_body->padata = calloc(1, sizeof(krb5_pa_data *));
- if (fast_req.req_body->padata == NULL)
- retval = ENOMEM;
+ fast_req.req_body->padata = calloc(1, sizeof(krb5_pa_data *));
+ if (fast_req.req_body->padata == NULL)
+ retval = ENOMEM;
}
fast_req.fast_options = state->fast_options;
if (retval == 0)
retval = encode_krb5_fast_req(&fast_req, &encoded_fast_req);
+ if (retval == 0) {
+ armored_req = calloc(1, sizeof(krb5_fast_armored_req));
+ if (armored_req == NULL)
+ retval = ENOMEM;
+ }
+ if (retval == 0)
+ armored_req->armor = state->armor;
+ if (retval == 0)
+ retval = krb5int_c_mandatory_cksumtype(context, state->armor_key->enctype,
+ &cksumtype);
+ if (retval ==0)
+ retval = krb5_c_make_checksum(context, cksumtype, state->armor_key,
+ KRB5_KEYUSAGE_FAST_REQ_CHKSUM, to_be_checksummed,
+ &armored_req->req_checksum);
+ if (retval == 0)
+ retval = krb5_encrypt_helper(context, state->armor_key,
+ KRB5_KEYUSAGE_FAST_ENC, encoded_fast_req,
+ &armored_req->enc_part);
+ if (retval == 0)
+ retval = encode_krb5_pa_fx_fast_request(armored_req, &encoded_armored_req);
if (retval==0) {
pa[0].pa_type = KRB5_PADATA_FX_FAST;
- pa[0].contents = (unsigned char *) encoded_fast_req->data;
- pa[0].length = encoded_fast_req->length;
+ pa[0].contents = (unsigned char *) encoded_armored_req->data;
+ pa[0].length = encoded_armored_req->length;
pa_array[0] = &pa[0];
}
if (state->cookie_contents.data) {
@@ -125,6 +227,12 @@ krb5int_fast_prep_req (krb5_context context, struct krb5int_fast_request_state *
*encoded_request = local_encoded_result;
local_encoded_result = NULL;
}
+ if (encoded_armored_req)
+ krb5_free_data(context, encoded_armored_req);
+ if (armored_req) {
+ armored_req->armor = NULL; /*owned by state*/
+ krb5_free_fast_armored_req(context, armored_req);
+ }
if (encoded_fast_req)
krb5_free_data(context, encoded_fast_req);
if (local_encoded_result)
diff --git a/src/lib/krb5/krb/fast.h b/src/lib/krb5/krb/fast.h
index 3225eab..acd12b3 100644
--- a/src/lib/krb5/krb/fast.h
+++ b/src/lib/krb5/krb/fast.h
@@ -62,6 +62,10 @@ krb5int_fast_make_state( krb5_context context, struct krb5int_fast_request_state
void
krb5int_fast_free_state( krb5_context , struct krb5int_fast_request_state *state);
+krb5_error_code krb5int_fast_as_armor
+(krb5_context context, struct krb5int_fast_request_state *state,
+ krb5_gic_opt_ext *opte,
+ krb5_kdc_req *request);
#endif
diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c
index 7bfca3f..eb23e54 100644
--- a/src/lib/krb5/krb/get_in_tkt.c
+++ b/src/lib/krb5/krb/get_in_tkt.c
@@ -1239,6 +1239,9 @@ krb5_get_init_creds(krb5_context context,
/* XXX Yuck. Old version. */
request.nonce = (krb5_int32) time_now;
}
+ ret = krb5int_fast_as_armor(context, fast_state, options, &request);
+ if (ret != 0)
+ goto cleanup;
/* give the preauth plugins a chance to prep the request body */
krb5_preauth_prepare_request(context, options, &request);
ret = krb5int_fast_prep_req_body(context, fast_state,
diff --git a/src/lib/krb5/krb/gic_opt.c b/src/lib/krb5/krb/gic_opt.c
index 348637c..72203f0 100644
--- a/src/lib/krb5/krb/gic_opt.c
+++ b/src/lib/krb5/krb/gic_opt.c
@@ -146,6 +146,8 @@ krb5int_gic_opte_private_free(krb5_context context, krb5_gic_opt_ext *opte)
/* Free up any private stuff */
if (opte->opt_private->preauth_data != NULL)
free_gic_opt_ext_preauth_data(context, opte);
+ if (opte->opt_private->fast_ccache_name)
+ free(opte->opt_private->fast_ccache_name);
free(opte->opt_private);
opte->opt_private = NULL;
return 0;
@@ -465,3 +467,21 @@ krb5_get_init_creds_opt_free_pa(krb5_context context,
}
free(preauth_data);
}
+krb5_error_code KRB5_CALLCONV krb5_get_init_creds_opt_set_fast_ccache_name
+(krb5_context context, krb5_get_init_creds_opt *opt, const char *ccache_name)
+{
+ krb5_error_code retval = 0;
+ krb5_gic_opt_ext *opte;
+
+ retval = krb5int_gic_opt_to_opte(context, opt, &opte, 0,
+ "krb5_get_init_creds_opt_set_fast_ccache_name");
+ if (retval)
+ return retval;
+ if (opte->opt_private->fast_ccache_name) {
+ free(opte->opt_private->fast_ccache_name);
+ }
+ opte->opt_private->fast_ccache_name = strdup(ccache_name);
+ if (opte->opt_private->fast_ccache_name == NULL)
+ retval = ENOMEM;
+ return retval;
+}
diff --git a/src/lib/krb5/krb/kfree.c b/src/lib/krb5/krb/kfree.c
index 5813fc0..d3ad3f7 100644
--- a/src/lib/krb5/krb/kfree.c
+++ b/src/lib/krb5/krb/kfree.c
@@ -830,6 +830,7 @@ void krb5_free_fast_finished
krb5_free_principal(context, val->client);
krb5_free_checksum_contents(context, &val->checksum);
krb5_free_checksum_contents(context, &val->ticket_checksum);
+ free(val);
}
void krb5_free_typed_data(krb5_context context, krb5_typed_data **in)
@@ -844,3 +845,16 @@ void krb5_free_typed_data(krb5_context context, krb5_typed_data **in)
}
free(in);
}
+
+void krb5_free_fast_armored_req(krb5_context context,
+ krb5_fast_armored_req *val)
+{
+ if (val == NULL)
+ return;
+ if (val->armor)
+ krb5_free_fast_armor(context, val->armor);
+ krb5_free_data_contents(context, &val->enc_part.ciphertext);
+ if (val->req_checksum.contents)
+ krb5_free_checksum_contents(context, &val->req_checksum);
+ free(val);
+}
diff --git a/src/lib/krb5/libkrb5.exports b/src/lib/krb5/libkrb5.exports
index 17b8fd3..45192f5 100644
--- a/src/lib/krb5/libkrb5.exports
+++ b/src/lib/krb5/libkrb5.exports
@@ -305,6 +305,7 @@ krb5_get_init_creds_opt_set_address_list
krb5_get_init_creds_opt_set_canonicalize
krb5_get_init_creds_opt_set_change_password_prompt
krb5_get_init_creds_opt_set_etype_list
+krb5_get_init_creds_opt_set_fast_ccache_name
krb5_get_init_creds_opt_set_forwardable
krb5_get_init_creds_opt_set_pa
krb5_get_init_creds_opt_set_preauth_list