svn rev #21591: branches/mskrb-integ/src/ include/ include/krb5/ lib/krb5/asn.1/ ...
lhoward@MIT.EDU
lhoward at MIT.EDU
Fri Dec 26 00:19:38 EST 2008
http://src.mit.edu/fisheye/changelog/krb5/?cs=21591
Commit By: lhoward
Log Message:
Implement RFC 4537 in libkrb5. If the AP_OPTS_ETYPE_NEGOTIATION flag is
passed to krb5_mk_req(), then a EtypeList constructed from the
auth_context or krb5 context list of permitted enctypes will be sent.
AP_OPTS_ETYPE_NEGOTIATION will be returned by krb5_rd_req() in
ap_req_options if a subkey of a different enctype should be negotiated.
AP_OPTS_ETYPE_NEGOTIATION is only valid with mutual authentication.
Changed Files:
U branches/mskrb-integ/src/include/k5-int.h
U branches/mskrb-integ/src/include/krb5/krb5.hin
U branches/mskrb-integ/src/lib/krb5/asn.1/asn1_k_decode.c
U branches/mskrb-integ/src/lib/krb5/asn.1/asn1_k_encode.c
U branches/mskrb-integ/src/lib/krb5/asn.1/krb5_decode.c
U branches/mskrb-integ/src/lib/krb5/krb/auth_con.c
U branches/mskrb-integ/src/lib/krb5/krb/auth_con.h
U branches/mskrb-integ/src/lib/krb5/krb/gen_subkey.c
U branches/mskrb-integ/src/lib/krb5/krb/kfree.c
U branches/mskrb-integ/src/lib/krb5/krb/mk_rep.c
U branches/mskrb-integ/src/lib/krb5/krb/mk_req_ext.c
U branches/mskrb-integ/src/lib/krb5/krb/rd_rep.c
U branches/mskrb-integ/src/lib/krb5/krb/rd_req_dec.c
Modified: branches/mskrb-integ/src/include/k5-int.h
===================================================================
--- branches/mskrb-integ/src/include/k5-int.h 2008-12-25 22:43:41 UTC (rev 21590)
+++ branches/mskrb-integ/src/include/k5-int.h 2008-12-26 05:19:33 UTC (rev 21591)
@@ -315,7 +315,7 @@
/* RFC 4537 */
typedef struct _krb5_etype_list {
- unsigned int length;
+ int length;
krb5_enctype *etypes;
} krb5_etype_list;
@@ -1230,6 +1230,8 @@
(krb5_context, krb5_pa_server_referral_data * );
void KRB5_CALLCONV krb5_free_pa_pac_req
(krb5_context, krb5_pa_pac_req * );
+void KRB5_CALLCONV krb5_free_etype_list
+ (krb5_context, krb5_etype_list * );
/* #include "krb5/wordsize.h" -- comes in through base-defs.h. */
#include "com_err.h"
@@ -1566,6 +1568,9 @@
krb5_error_code encode_krb5_pa_pac_req
(const krb5_pa_pac_req * , krb5_data **);
+krb5_error_code encode_krb5_etype_list
+ (const krb5_etype_list * , krb5_data **);
+
/*************************************************************************
* End of prototypes for krb5_encode.c
*************************************************************************/
@@ -1722,6 +1727,9 @@
krb5_error_code decode_krb5_pa_pac_req
(const krb5_data *, krb5_pa_pac_req **);
+krb5_error_code decode_krb5_etype_list
+ (const krb5_data *, krb5_etype_list **);
+
struct _krb5_key_data; /* kdb.h */
struct ldap_seqof_key_data {
@@ -1892,7 +1900,8 @@
krb5_error_code
krb5int_generate_and_save_subkey (krb5_context, krb5_auth_context,
- krb5_keyblock * /* Old keyblock, not new! */);
+ krb5_keyblock * /* Old keyblock, not new! */,
+ krb5_enctype);
/* set and change password helpers */
@@ -2413,6 +2422,11 @@
krb5_error_code krb5_generate_subkey
(krb5_context,
const krb5_keyblock *, krb5_keyblock **);
+krb5_error_code krb5_generate_subkey_extended
+ (krb5_context,
+ const krb5_keyblock *,
+ krb5_enctype,
+ krb5_keyblock **);
krb5_error_code krb5_generate_seq_number
(krb5_context,
const krb5_keyblock *, krb5_ui_4 *);
Modified: branches/mskrb-integ/src/include/krb5/krb5.hin
===================================================================
--- branches/mskrb-integ/src/include/krb5/krb5.hin 2008-12-25 22:43:41 UTC (rev 21590)
+++ branches/mskrb-integ/src/include/krb5/krb5.hin 2008-12-26 05:19:33 UTC (rev 21591)
@@ -838,10 +838,10 @@
/* #define AP_OPTS_RESERVED 0x00000010 */
/* #define AP_OPTS_RESERVED 0x00000008 */
/* #define AP_OPTS_RESERVED 0x00000004 */
-/* #define AP_OPTS_RESERVED 0x00000002 */
-#define AP_OPTS_USE_SUBKEY 0x00000001
+#define AP_OPTS_ETYPE_NEGOTIATION 0x00000002
+#define AP_OPTS_USE_SUBKEY 0x00000001
-#define AP_OPTS_WIRE_MASK 0xfffffff0
+#define AP_OPTS_WIRE_MASK 0xfffffff0
/* definitions for ad_type fields. */
#define AD_TYPE_RESERVED 0x8000
@@ -2502,13 +2502,13 @@
krb5_error_code KRB5_CALLCONV
krb5_decode_authdata_container(krb5_context context,
krb5_authdatatype type,
- const krb5_authdata *if_relevant,
+ const krb5_authdata *container,
krb5_authdata ***authdata);
krb5_error_code KRB5_CALLCONV
krb5_encode_authdata_container(krb5_context context,
krb5_authdatatype type,
krb5_authdata * const*authdata,
- krb5_authdata ***if_relevant_p);
+ krb5_authdata ***container);
/*
* Windows PAC
Modified: branches/mskrb-integ/src/lib/krb5/asn.1/asn1_k_decode.c
===================================================================
--- branches/mskrb-integ/src/lib/krb5/asn.1/asn1_k_decode.c 2008-12-25 22:43:41 UTC (rev 21590)
+++ branches/mskrb-integ/src/lib/krb5/asn.1/asn1_k_decode.c 2008-12-26 05:19:33 UTC (rev 21591)
@@ -1226,6 +1226,15 @@
cleanup();
}
+asn1_error_code asn1_decode_etype_list(asn1buf *buf, krb5_etype_list *val)
+{
+ setup();
+ { begin_structure();
+ end_structure();
+ }
+ cleanup();
+}
+
#ifndef DISABLE_PKINIT
/* PKINIT */
Modified: branches/mskrb-integ/src/lib/krb5/asn.1/asn1_k_encode.c
===================================================================
--- branches/mskrb-integ/src/lib/krb5/asn.1/asn1_k_encode.c 2008-12-25 22:43:41 UTC (rev 21590)
+++ branches/mskrb-integ/src/lib/krb5/asn.1/asn1_k_encode.c 2008-12-26 05:19:33 UTC (rev 21591)
@@ -1173,6 +1173,10 @@
DEFSEQTYPE(pa_pac_request, krb5_pa_pac_req, pa_pac_request_fields, 0);
#endif
+/* RFC 4537 */
+DEFFIELDTYPE(etype_list, krb5_etype_list,
+ FIELDOF_SEQOF_INT32(krb5_etype_list, int32_ptr, etypes, length, -1));
+
/* Exported complete encoders -- these produce a krb5_data with
the encoding in the correct byte order. */
@@ -1237,6 +1241,7 @@
MAKE_FULL_ENCODER(encode_krb5_pa_for_user, pa_for_user);
MAKE_FULL_ENCODER(encode_krb5_pa_svr_referral_data, pa_svr_referral_data);
MAKE_FULL_ENCODER(encode_krb5_pa_server_referral_data, pa_server_referral_data);
+MAKE_FULL_ENCODER(encode_krb5_etype_list, etype_list);
@@ -1244,7 +1249,6 @@
-
#ifndef DISABLE_PKINIT
/*
* PKINIT
Modified: branches/mskrb-integ/src/lib/krb5/asn.1/krb5_decode.c
===================================================================
--- branches/mskrb-integ/src/lib/krb5/asn.1/krb5_decode.c 2008-12-25 22:43:41 UTC (rev 21590)
+++ branches/mskrb-integ/src/lib/krb5/asn.1/krb5_decode.c 2008-12-26 05:19:33 UTC (rev 21591)
@@ -987,6 +987,17 @@
cleanup(free);
}
+krb5_error_code decode_krb5_etype_list(const krb5_data *code, krb5_etype_list **rep)
+{
+ setup_buf_only();
+ alloc_field(*rep, krb5_etype_list);
+
+ retval = asn1_decode_sequence_of_enctype(&buf, &(*rep)->length, &(*rep)->etypes);
+ if (retval) clean_return(retval);
+
+ cleanup(free);
+}
+
#ifndef DISABLE_PKINIT
krb5_error_code decode_krb5_pa_pk_as_req(const krb5_data *code, krb5_pa_pk_as_req **rep)
{
Modified: branches/mskrb-integ/src/lib/krb5/krb/auth_con.c
===================================================================
--- branches/mskrb-integ/src/lib/krb5/krb/auth_con.c 2008-12-25 22:43:41 UTC (rev 21590)
+++ branches/mskrb-integ/src/lib/krb5/krb/auth_con.c 2008-12-26 05:19:33 UTC (rev 21591)
@@ -34,8 +34,9 @@
(*auth_context)->req_cksumtype = context->default_ap_req_sumtype;
(*auth_context)->safe_cksumtype = context->default_safe_sumtype;
- (*auth_context) -> checksum_func = NULL;
+ (*auth_context)->checksum_func = NULL;
(*auth_context)->checksum_func_data = NULL;
+ (*auth_context)->negotiated_etype = ENCTYPE_NULL;
(*auth_context)->magic = KV5M_AUTH_CONTEXT;
return 0;
}
Modified: branches/mskrb-integ/src/lib/krb5/krb/auth_con.h
===================================================================
--- branches/mskrb-integ/src/lib/krb5/krb/auth_con.h 2008-12-25 22:43:41 UTC (rev 21590)
+++ branches/mskrb-integ/src/lib/krb5/krb/auth_con.h 2008-12-26 05:19:33 UTC (rev 21591)
@@ -21,8 +21,9 @@
krb5_pointer i_vector; /* mk_priv, rd_priv only */
krb5_rcache rcache;
krb5_enctype * permitted_etypes; /* rd_req */
- krb5_mk_req_checksum_func checksum_func;
- void *checksum_func_data;
+ krb5_mk_req_checksum_func checksum_func;
+ void *checksum_func_data;
+ krb5_enctype negotiated_etype;
};
Modified: branches/mskrb-integ/src/lib/krb5/krb/gen_subkey.c
===================================================================
--- branches/mskrb-integ/src/lib/krb5/krb/gen_subkey.c 2008-12-25 22:43:41 UTC (rev 21590)
+++ branches/mskrb-integ/src/lib/krb5/krb/gen_subkey.c 2008-12-26 05:19:33 UTC (rev 21591)
@@ -40,7 +40,10 @@
}
krb5_error_code
-krb5_generate_subkey(krb5_context context, const krb5_keyblock *key, krb5_keyblock **subkey)
+krb5_generate_subkey_extended(krb5_context context,
+ const krb5_keyblock *key,
+ krb5_enctype enctype,
+ krb5_keyblock **subkey)
{
krb5_error_code retval;
krb5_data seed;
@@ -52,10 +55,16 @@
if ((*subkey = (krb5_keyblock *) malloc(sizeof(krb5_keyblock))) == NULL)
return(ENOMEM);
- if ((retval = krb5_c_make_random_key(context, key->enctype, *subkey))) {
+ if ((retval = krb5_c_make_random_key(context, enctype, *subkey))) {
krb5_xfree(*subkey);
return(retval);
}
return(0);
}
+
+krb5_error_code
+krb5_generate_subkey(krb5_context context, const krb5_keyblock *key, krb5_keyblock **subkey)
+{
+ return krb5_generate_subkey_extended(context, key, key->enctype, subkey);
+}
Modified: branches/mskrb-integ/src/lib/krb5/krb/kfree.c
===================================================================
--- branches/mskrb-integ/src/lib/krb5/krb/kfree.c 2008-12-25 22:43:41 UTC (rev 21590)
+++ branches/mskrb-integ/src/lib/krb5/krb/kfree.c 2008-12-26 05:19:33 UTC (rev 21591)
@@ -799,3 +799,13 @@
krb5_xfree(req);
}
+void KRB5_CALLCONV
+krb5_free_etype_list(krb5_context context,
+ krb5_etype_list *etypes)
+{
+ if (etypes != NULL) {
+ if (etypes->etypes != NULL)
+ krb5_xfree(etypes->etypes);
+ krb5_xfree(etypes);
+ }
+}
Modified: branches/mskrb-integ/src/lib/krb5/krb/mk_rep.c
===================================================================
--- branches/mskrb-integ/src/lib/krb5/krb/mk_rep.c 2008-12-25 22:43:41 UTC (rev 21590)
+++ branches/mskrb-integ/src/lib/krb5/krb/mk_rep.c 2008-12-26 05:19:33 UTC (rev 21591)
@@ -95,8 +95,11 @@
if (dce_style)
repl.subkey = NULL;
else if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_USE_SUBKEY) {
+ assert(auth_context->negotiated_etype != ENCTYPE_NULL);
+
retval = krb5int_generate_and_save_subkey (context, auth_context,
- auth_context->keyblock);
+ auth_context->keyblock,
+ auth_context->negotiated_etype);
if (retval)
return retval;
repl.subkey = auth_context->send_subkey;
Modified: branches/mskrb-integ/src/lib/krb5/krb/mk_req_ext.c
===================================================================
--- branches/mskrb-integ/src/lib/krb5/krb/mk_req_ext.c 2008-12-25 22:43:41 UTC (rev 21590)
+++ branches/mskrb-integ/src/lib/krb5/krb/mk_req_ext.c 2008-12-26 05:19:33 UTC (rev 21591)
@@ -64,16 +64,25 @@
returns system errors
*/
+static krb5_error_code
+make_etype_list(krb5_context context,
+ krb5_enctype *permitted_etypes,
+ krb5_enctype tkt_enctype,
+ krb5_authdata ***authdata);
+
static krb5_error_code
krb5_generate_authenticator (krb5_context,
krb5_authenticator *, krb5_principal,
krb5_checksum *, krb5_keyblock *,
- krb5_ui_4, krb5_authdata ** );
+ krb5_ui_4, krb5_authdata **,
+ krb5_enctype *permitted_etypes,
+ krb5_enctype tkt_enctype);
krb5_error_code
krb5int_generate_and_save_subkey (krb5_context context,
krb5_auth_context auth_context,
- krb5_keyblock *keyblock)
+ krb5_keyblock *keyblock,
+ krb5_enctype enctype)
{
/* Provide some more fodder for random number code.
This isn't strong cryptographically; the point here is not
@@ -92,7 +101,8 @@
if (auth_context->send_subkey)
krb5_free_keyblock(context, auth_context->send_subkey);
- if ((retval = krb5_generate_subkey(context, keyblock, &auth_context->send_subkey)))
+ if ((retval = krb5_generate_subkey_extended(context, keyblock, enctype,
+ &auth_context->send_subkey)))
return retval;
if (auth_context->recv_subkey)
@@ -116,18 +126,23 @@
krb5_checksum checksum;
krb5_checksum *checksump = 0;
krb5_auth_context new_auth_context;
+ krb5_enctype *permitted_etypes = NULL;
krb5_ap_req request;
krb5_data *scratch = 0;
krb5_data *toutbuf;
request.ap_options = ap_req_options & AP_OPTS_WIRE_MASK;
- request.authenticator.ciphertext.data = 0;
+ request.authenticator.ciphertext.data = NULL;
request.ticket = 0;
if (!in_creds->ticket.length)
return(KRB5_NO_TKT_SUPPLIED);
+ if ((ap_req_options & AP_OPTS_ETYPE_NEGOTIATION) &&
+ !(ap_req_options & AP_OPTS_MUTUAL_REQUIRED))
+ return(EINVAL);
+
/* we need a native ticket */
if ((retval = decode_krb5_ticket(&(in_creds)->ticket, &request.ticket)))
return(retval);
@@ -174,7 +189,8 @@
if ((ap_req_options & AP_OPTS_USE_SUBKEY)&&(!(*auth_context)->send_subkey)) {
retval = krb5int_generate_and_save_subkey (context, *auth_context,
- &in_creds->keyblock);
+ &in_creds->keyblock,
+ in_creds->keyblock.enctype);
if (retval)
goto cleanup;
}
@@ -205,12 +221,23 @@
goto cleanup_cksum;
}
+ if (ap_req_options & AP_OPTS_ETYPE_NEGOTIATION) {
+ if ((*auth_context)->permitted_etypes == NULL) {
+ retval = krb5_get_permitted_enctypes(context, &permitted_etypes);
+ if (retval)
+ goto cleanup_cksum;
+ } else
+ permitted_etypes = (*auth_context)->permitted_etypes;
+ }
+
if ((retval = krb5_generate_authenticator(context,
(*auth_context)->authentp,
- (in_creds)->client, checksump,
+ in_creds->client, checksump,
(*auth_context)->send_subkey,
(*auth_context)->local_seq_number,
- (in_creds)->authdata)))
+ in_creds->authdata,
+ permitted_etypes,
+ in_creds->keyblock.enctype)))
goto cleanup_cksum;
/* encode the authenticator */
@@ -223,7 +250,6 @@
*/
(*auth_context)->authentp->client = NULL;
(*auth_context)->authentp->checksum = NULL;
- (*auth_context)->authentp->authorization_data = NULL;
/* call the encryption routine */
if ((retval = krb5_encrypt_helper(context, &in_creds->keyblock,
@@ -242,6 +268,9 @@
free(checksump->contents);
cleanup:
+ if (permitted_etypes &&
+ permitted_etypes != (*auth_context)->permitted_etypes)
+ krb5_xfree(permitted_etypes);
if (request.ticket)
krb5_free_ticket(context, request.ticket);
if (request.authenticator.ciphertext.data) {
@@ -261,7 +290,9 @@
krb5_generate_authenticator(krb5_context context, krb5_authenticator *authent,
krb5_principal client, krb5_checksum *cksum,
krb5_keyblock *key, krb5_ui_4 seq_number,
- krb5_authdata **authorization)
+ krb5_authdata **authorization,
+ krb5_enctype *permitted_etypes,
+ krb5_enctype tkt_enctype)
{
krb5_error_code retval;
@@ -274,7 +305,114 @@
} else
authent->subkey = 0;
authent->seq_number = seq_number;
- authent->authorization_data = authorization;
+ authent->authorization_data = NULL;
+ if (authorization != NULL) {
+ retval = krb5_copy_authdata(context, authorization,
+ &authent->authorization_data);
+ if (retval)
+ return retval;
+ }
+ if (permitted_etypes != NULL) {
+ retval = make_etype_list(context, permitted_etypes, tkt_enctype,
+ &authent->authorization_data);
+ if (retval)
+ return retval;
+ }
+
return(krb5_us_timeofday(context, &authent->ctime, &authent->cusec));
}
+
+/* RFC 4537 */
+static krb5_error_code
+make_etype_list(krb5_context context,
+ krb5_enctype *permitted_etypes,
+ krb5_enctype tkt_enctype,
+ krb5_authdata ***authdata)
+{
+ krb5_error_code code;
+ krb5_etype_list etypes;
+ krb5_data *enc_etype_list;
+ krb5_data *ad_if_relevant;
+ krb5_authdata *etype_adata[2], etype_adatum, **adata;
+ int i;
+
+ etypes.etypes = permitted_etypes;
+
+ for (etypes.length = 0;
+ etypes.etypes[etypes.length] != ENCTYPE_NULL;
+ etypes.length++)
+ ;
+
+ /*
+ * RFC 4537:
+ * If the enctype of the ticket session key is included in the enctype
+ * list sent by the client, it SHOULD be the last on the list.
+ */
+ for (i = 0; i < etypes.length; i++) {
+ if (etypes.etypes[i] == tkt_enctype) {
+ krb5_enctype etype;
+
+ etype = etypes.etypes[etypes.length - 1];
+ etypes.etypes[etypes.length - 1] = tkt_enctype;
+ etypes.etypes[i] = etype;
+ break;
+ }
+ }
+
+ code = encode_krb5_etype_list(&etypes, &enc_etype_list);
+ if (code) {
+ return code;
+ }
+
+ etype_adatum.magic = KV5M_AUTHDATA;
+ etype_adatum.ad_type = KRB5_AUTHDATA_ETYPE_NEGOTIATION;
+ etype_adatum.length = enc_etype_list->length;
+ etype_adatum.contents = (krb5_octet *)enc_etype_list->data;
+
+ etype_adata[0] = &etype_adatum;
+ etype_adata[1] = NULL;
+
+ /* Wrap in AD-IF-RELEVANT container */
+ code = encode_krb5_authdata(etype_adata, &ad_if_relevant);
+ if (code) {
+ krb5_free_data(context, enc_etype_list);
+ return code;
+ }
+
+ krb5_free_data(context, enc_etype_list);
+
+ adata = *authdata;
+ if (adata == NULL) {
+ adata = (krb5_authdata **)calloc(2, sizeof(krb5_authdata *));
+ i = 0;
+ } else {
+ for (i = 0; adata[i] != NULL; i++)
+ ;
+
+ adata = (krb5_authdata **)realloc(*authdata,
+ (i + 2) * sizeof(krb5_authdata *));
+ }
+ if (adata == NULL) {
+ krb5_free_data(context, ad_if_relevant);
+ return ENOMEM;
+ }
+
+ adata[i] = (krb5_authdata *)malloc(sizeof(krb5_authdata));
+ if (adata[i] == NULL) {
+ krb5_free_data(context, ad_if_relevant);
+ return ENOMEM;
+ }
+ adata[i]->magic = KV5M_AUTHDATA;
+ adata[i]->ad_type = KRB5_AUTHDATA_IF_RELEVANT;
+ adata[i]->length = ad_if_relevant->length;
+ adata[i]->contents = (krb5_octet *)ad_if_relevant->data;
+ krb5_xfree(ad_if_relevant); /* contents owned by adata[i] */
+
+ adata[i + 1] = NULL;
+
+ *authdata = adata;
+
+ return 0;
+}
+
Modified: branches/mskrb-integ/src/lib/krb5/krb/rd_rep.c
===================================================================
--- branches/mskrb-integ/src/lib/krb5/krb/rd_rep.c 2008-12-25 22:43:41 UTC (rev 21590)
+++ branches/mskrb-integ/src/lib/krb5/krb/rd_rep.c 2008-12-26 05:19:33 UTC (rev 21591)
@@ -129,6 +129,8 @@
krb5_free_keyblock(context, auth_context->send_subkey);
auth_context->send_subkey = NULL;
}
+ /* not used for anything yet */
+ auth_context->negotiated_etype = (*repl)->subkey->enctype;
}
/* Get remote sequence number */
Modified: branches/mskrb-integ/src/lib/krb5/krb/rd_req_dec.c
===================================================================
--- branches/mskrb-integ/src/lib/krb5/krb/rd_req_dec.c 2008-12-25 22:43:41 UTC (rev 21590)
+++ branches/mskrb-integ/src/lib/krb5/krb/rd_req_dec.c 2008-12-26 05:19:33 UTC (rev 21591)
@@ -62,6 +62,19 @@
static krb5_error_code decrypt_authenticator
(krb5_context, const krb5_ap_req *, krb5_authenticator **,
int);
+static krb5_error_code
+decode_etype_list(krb5_context context,
+ const krb5_authenticator *authp,
+ krb5_enctype **desired_etypes,
+ int *desired_etypes_len);
+static krb5_error_code
+negotiate_etype(krb5_context context,
+ const krb5_enctype *desired_etypes,
+ int desired_etypes_len,
+ int mandatory_etypes_index,
+ const krb5_enctype *permitted_etypes,
+ int permitted_etypes_len,
+ krb5_enctype *negotiated_etype);
krb5_error_code
krb5int_check_clockskew(krb5_context context, krb5_timestamp date)
@@ -172,8 +185,13 @@
krb5_ticket **ticket, int check_valid_flag)
{
krb5_error_code retval = 0;
- krb5_principal_data princ_data;
-
+ krb5_principal_data princ_data;
+ krb5_enctype *desired_etypes = NULL;
+ int desired_etypes_len = 0;
+ int rfc4537_etypes_len = 0;
+ krb5_enctype *permitted_etypes = NULL;
+ int permitted_etypes_len = 0;
+
req->ticket->enc_part2 = NULL;
if (server && krb5_is_referral_realm(&server->realm)) {
char *realm;
@@ -340,126 +358,59 @@
}
}
- /* check if the various etypes are permitted */
+ /* read RFC 4537 etype list from sender */
+ retval = decode_etype_list(context,
+ (*auth_context)->authentp,
+ &desired_etypes,
+ &rfc4537_etypes_len);
+ if (retval != 0)
+ goto cleanup;
- if ((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_PERMIT_ALL) {
- /* no etype check needed */;
- } else if ((*auth_context)->permitted_etypes == NULL) {
- int etype;
- size_t size_etype_enc = 3 * sizeof(krb5_enctype); /* upto three types */
- size_t size_etype_bool = 3 * sizeof(krb5_boolean);
- krb5_etypes_permitted etypes;
- memset(&etypes, 0, sizeof etypes);
+ if (desired_etypes == NULL)
+ desired_etypes = (krb5_enctype *)calloc(4, sizeof(krb5_enctype));
+ else
+ desired_etypes = (krb5_enctype *)realloc(desired_etypes,
+ (rfc4537_etypes_len + 4) *
+ sizeof(krb5_enctype));
+ if (desired_etypes == NULL) {
+ retval = ENOMEM;
+ goto cleanup;
+ }
- etypes.etype = (krb5_enctype*) malloc(size_etype_enc);
- if (etypes.etype == NULL) {
- retval = ENOMEM;
- goto cleanup;
- }
- etypes.etype_ok = (krb5_boolean*) malloc(size_etype_bool);
- if (etypes.etype_ok == NULL) {
- retval = ENOMEM;
- free(etypes.etype);
- goto cleanup;
- }
- memset(etypes.etype, 0, size_etype_enc);
- memset(etypes.etype_ok, 0, size_etype_bool);
+ desired_etypes_len = rfc4537_etypes_len;
- etypes.etype[etypes.etype_count++] = req->ticket->enc_part.enctype;
- etypes.etype[etypes.etype_count++] = req->ticket->enc_part2->session->enctype;
- if ((*auth_context)->authentp->subkey) {
- etypes.etype[etypes.etype_count++] = (*auth_context)->authentp->subkey->enctype;
- }
+ if ((*auth_context)->authentp->subkey != NULL)
+ desired_etypes[desired_etypes_len++] = (*auth_context)->authentp->subkey->enctype;
+ desired_etypes[desired_etypes_len++] = req->ticket->enc_part2->session->enctype;
+ desired_etypes[desired_etypes_len++] = req->ticket->enc_part.enctype;
+ desired_etypes[desired_etypes_len] = ENCTYPE_NULL;
- retval = krb5_is_permitted_enctype_ext(context, &etypes);
-
-#if 0
- /* check against the default set */
- if ((!krb5_is_permitted_enctype(context,
- etype = req->ticket->enc_part.enctype)) ||
- (!krb5_is_permitted_enctype(context,
- etype = req->ticket->enc_part2->session->enctype)) ||
- (((*auth_context)->authentp->subkey) &&
- !krb5_is_permitted_enctype(context,
- etype = (*auth_context)->authentp->subkey->enctype))) {
-#endif
- if (retval == 0 /* all etypes are not permitted */ ||
- (!etypes.etype_ok[0] || !etypes.etype_ok[1] ||
- (((*auth_context)->authentp->subkey) && !etypes.etype_ok[etypes.etype_count-1]))) {
- char enctype_name[30];
- retval = KRB5_NOPERM_ETYPE;
-
- if (!etypes.etype_ok[0]) {
- etype = etypes.etype[1];
- } else if (!etypes.etype_ok[1]) {
- etype = etypes.etype[1];
- } else {
- etype = etypes.etype[2];
- }
- free(etypes.etype);
- free(etypes.etype_ok);
-
- if (krb5_enctype_to_string(etype, enctype_name, sizeof(enctype_name)) == 0)
- krb5_set_error_message(context, retval,
- "Encryption type %s not permitted",
- enctype_name);
- goto cleanup;
+ if (((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_PERMIT_ALL) == 0) {
+ if ((*auth_context)->permitted_etypes != NULL) {
+ permitted_etypes = (*auth_context)->permitted_etypes;
+ } else {
+ retval = krb5_get_permitted_enctypes(context, &permitted_etypes);
+ if (retval != 0)
+ goto cleanup;
}
- free(etypes.etype);
- free(etypes.etype_ok);
+ for (permitted_etypes_len = 0;
+ permitted_etypes[permitted_etypes_len] != ENCTYPE_NULL;
+ permitted_etypes_len++)
+ ;
} else {
- /* check against the set in the auth_context */
- int i;
-
- for (i=0; (*auth_context)->permitted_etypes[i]; i++)
- if ((*auth_context)->permitted_etypes[i] ==
- req->ticket->enc_part.enctype)
- break;
- if (!(*auth_context)->permitted_etypes[i]) {
- char enctype_name[30];
- retval = KRB5_NOPERM_ETYPE;
- if (krb5_enctype_to_string(req->ticket->enc_part.enctype,
- enctype_name, sizeof(enctype_name)) == 0)
- krb5_set_error_message(context, retval,
- "Encryption type %s not permitted",
- enctype_name);
- goto cleanup;
- }
-
- for (i=0; (*auth_context)->permitted_etypes[i]; i++)
- if ((*auth_context)->permitted_etypes[i] ==
- req->ticket->enc_part2->session->enctype)
- break;
- if (!(*auth_context)->permitted_etypes[i]) {
- char enctype_name[30];
- retval = KRB5_NOPERM_ETYPE;
- if (krb5_enctype_to_string(req->ticket->enc_part2->session->enctype,
- enctype_name, sizeof(enctype_name)) == 0)
- krb5_set_error_message(context, retval,
- "Encryption type %s not permitted",
- enctype_name);
- goto cleanup;
- }
-
- if ((*auth_context)->authentp->subkey) {
- for (i=0; (*auth_context)->permitted_etypes[i]; i++)
- if ((*auth_context)->permitted_etypes[i] ==
- (*auth_context)->authentp->subkey->enctype)
- break;
- if (!(*auth_context)->permitted_etypes[i]) {
- char enctype_name[30];
- retval = KRB5_NOPERM_ETYPE;
- if (krb5_enctype_to_string((*auth_context)->authentp->subkey->enctype,
- enctype_name,
- sizeof(enctype_name)) == 0)
- krb5_set_error_message(context, retval,
- "Encryption type %s not permitted",
- enctype_name);
- goto cleanup;
- }
- }
+ permitted_etypes = NULL;
+ permitted_etypes_len = 0;
}
+ /* check if the various etypes are permitted */
+ retval = negotiate_etype(context,
+ desired_etypes, desired_etypes_len,
+ rfc4537_etypes_len,
+ permitted_etypes, permitted_etypes_len,
+ &(*auth_context)->negotiated_etype);
+ if (retval != 0)
+ goto cleanup;
+
(*auth_context)->remote_seq_number = (*auth_context)->authentp->seq_number;
if ((*auth_context)->authentp->subkey) {
if ((retval = krb5_copy_keyblock(context,
@@ -498,11 +449,20 @@
if (ticket)
if ((retval = krb5_copy_ticket(context, req->ticket, ticket)))
goto cleanup;
- if (ap_req_options)
+ if (ap_req_options) {
*ap_req_options = req->ap_options;
+ if ((*auth_context)->negotiated_etype != (*auth_context)->keyblock->enctype)
+ *ap_req_options |= AP_OPTS_ETYPE_NEGOTIATION;
+ }
+
retval = 0;
cleanup:
+ if (desired_etypes != NULL)
+ krb5_xfree(desired_etypes);
+ if (permitted_etypes != NULL &&
+ permitted_etypes != (*auth_context)->permitted_etypes)
+ krb5_xfree(permitted_etypes);
if (server == &princ_data)
krb5_free_default_realm(context, princ_data.realm.data);
if (retval) {
@@ -581,3 +541,124 @@
}
#endif
+static krb5_error_code
+negotiate_etype(krb5_context context,
+ const krb5_enctype *desired_etypes,
+ int desired_etypes_len,
+ int mandatory_etypes_index,
+ const krb5_enctype *permitted_etypes,
+ int permitted_etypes_len,
+ krb5_enctype *negotiated_etype)
+{
+ int i, j;
+
+ *negotiated_etype = ENCTYPE_NULL;
+
+ for (i = mandatory_etypes_index; i < desired_etypes_len; i++) {
+ krb5_boolean permitted = FALSE;
+
+ for (j = 0; j < permitted_etypes_len; j++) {
+ if (desired_etypes[i] == permitted_etypes[j]) {
+ permitted = TRUE;
+ break;
+ }
+ }
+
+ if (permitted == FALSE) {
+ char enctype_name[30];
+
+ if (krb5_enctype_to_string(desired_etypes[i],
+ enctype_name,
+ sizeof(enctype_name)) == 0)
+ krb5_set_error_message(context, KRB5_NOPERM_ETYPE,
+ "Encryption type %s not permitted",
+ enctype_name);
+ return KRB5_NOPERM_ETYPE;
+ }
+ }
+
+ for (j = 0; j < permitted_etypes_len; j++) {
+ for (i = 0; i < desired_etypes_len; i++) {
+ if (desired_etypes[i] == permitted_etypes[j]) {
+ *negotiated_etype = permitted_etypes[j];
+ return 0;
+ }
+ }
+ }
+
+ /*NOTREACHED*/
+ return KRB5_NOPERM_ETYPE;
+}
+
+static krb5_error_code
+decode_etype_list(krb5_context context,
+ const krb5_authenticator *authp,
+ krb5_enctype **desired_etypes,
+ int *desired_etypes_len)
+{
+ krb5_error_code code;
+ krb5_authdata **ad_if_relevant = NULL;
+ krb5_authdata *etype_adata = NULL;
+ krb5_etype_list *etype_list = NULL;
+ int i, j;
+ krb5_data data;
+
+ *desired_etypes = NULL;
+
+ if (authp->authorization_data == NULL)
+ return 0;
+
+ /*
+ * RFC 4537 says that ETYPE_NEGOTIATION auth data should be wrapped
+ * in AD_IF_RELEVANT, but we handle the case where it is mandatory.
+ */
+ for (i = 0; authp->authorization_data[i] != NULL; i++) {
+ switch (authp->authorization_data[i]->ad_type) {
+ case KRB5_AUTHDATA_IF_RELEVANT:
+ code = krb5_decode_authdata_container(context,
+ KRB5_AUTHDATA_IF_RELEVANT,
+ authp->authorization_data[i],
+ &ad_if_relevant);
+ if (code != 0)
+ continue;
+
+ for (j = 0; ad_if_relevant[j] != NULL; j++) {
+ if (ad_if_relevant[j]->ad_type == KRB5_AUTHDATA_ETYPE_NEGOTIATION) {
+ etype_adata = ad_if_relevant[j];
+ break;
+ }
+ }
+ if (etype_adata == NULL) {
+ krb5_free_authdata(context, ad_if_relevant);
+ ad_if_relevant = NULL;
+ }
+ break;
+ case KRB5_AUTHDATA_ETYPE_NEGOTIATION:
+ etype_adata = authp->authorization_data[i];
+ break;
+ default:
+ break;
+ }
+ if (etype_adata != NULL)
+ break;
+ }
+
+ if (etype_adata == NULL)
+ return 0;
+
+ data.data = (char *)etype_adata->contents;
+ data.length = etype_adata->length;
+
+ code = decode_krb5_etype_list(&data, &etype_list);
+ if (code == 0) {
+ *desired_etypes = etype_list->etypes;
+ *desired_etypes_len = etype_list->length;
+ krb5_xfree(etype_list);
+ }
+
+ if (ad_if_relevant != NULL)
+ krb5_free_authdata(context, ad_if_relevant);
+
+ return code;
+}
+
More information about the cvs-krb5
mailing list