diff options
| author | Marc Horowitz <marc@mit.edu> | 1998-10-30 02:56:35 +0000 |
|---|---|---|
| committer | Marc Horowitz <marc@mit.edu> | 1998-10-30 02:56:35 +0000 |
| commit | 1440ab035ba04550ddbbfbff1ee9b5571e3d95db (patch) | |
| tree | 9d5e8d2e151a930e044c7d0f7c64053d244577a0 /src/lib/gssapi | |
| parent | 61ddbf948ba6ee70c1bc049268c3dfa73bc9983e (diff) | |
| download | krb5-1440ab035ba04550ddbbfbff1ee9b5571e3d95db.tar.gz krb5-1440ab035ba04550ddbbfbff1ee9b5571e3d95db.tar.xz krb5-1440ab035ba04550ddbbfbff1ee9b5571e3d95db.zip | |
pull up 3des implementation from the marc-3des branch
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@11001 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/lib/gssapi')
30 files changed, 3118 insertions, 963 deletions
diff --git a/src/lib/gssapi/Makefile.in b/src/lib/gssapi/Makefile.in index 6835596f7..843207133 100644 --- a/src/lib/gssapi/Makefile.in +++ b/src/lib/gssapi/Makefile.in @@ -9,7 +9,7 @@ LOCAL_SUBDIRS= generic krb5 MAC_SUBDIRS = generic krb5 LIB=gssapi_krb5 -LIBMAJOR=1 +LIBMAJOR=2 LIBMINOR=1 STOBJLISTS=generic/OBJS.ST krb5/OBJS.ST SHLIB_EXPDEPS=\ diff --git a/src/lib/gssapi/generic/ChangeLog b/src/lib/gssapi/generic/ChangeLog index 74f13a4a3..601ca76f6 100644 --- a/src/lib/gssapi/generic/ChangeLog +++ b/src/lib/gssapi/generic/ChangeLog @@ -1,3 +1,8 @@ +1998-10-27 Marc Horowitz <marc@mit.edu> + + * gssapi.hin: define GSS_S_DUPLICATE_ELEMENT, GSS_S_NAME_NOT_MN, + and GSS_S_GAP_TOKEN as per gss v2 c bindings + 1998-06-08 Theodore Ts'o <tytso@rsts-11.mit.edu> * oid_ops.c (generic_gss_release_oid): Recognize our own "self" diff --git a/src/lib/gssapi/generic/gssapi.hin b/src/lib/gssapi/generic/gssapi.hin index d00e19ab9..a30b79431 100644 --- a/src/lib/gssapi/generic/gssapi.hin +++ b/src/lib/gssapi/generic/gssapi.hin @@ -307,11 +307,10 @@ typedef int gss_cred_usage_t; #define GSS_S_BAD_QOP (((OM_uint32) 14ul) << GSS_C_ROUTINE_ERROR_OFFSET) #define GSS_S_UNAUTHORIZED (((OM_uint32) 15ul) << GSS_C_ROUTINE_ERROR_OFFSET) #define GSS_S_UNAVAILABLE (((OM_uint32) 16ul) << GSS_C_ROUTINE_ERROR_OFFSET) -/* - * XXX new functions. Check to get official error number assigments? - */ #define GSS_S_DUPLICATE_ELEMENT \ (((OM_uint32) 17ul) << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_NAME_NOT_MN \ + (((OM_uint32) 18ul) << GSS_C_ROUTINE_ERROR_OFFSET) /* * Supplementary info bits: @@ -320,9 +319,6 @@ typedef int gss_cred_usage_t; #define GSS_S_DUPLICATE_TOKEN (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 1)) #define GSS_S_OLD_TOKEN (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 2)) #define GSS_S_UNSEQ_TOKEN (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 3)) -/* - * XXX not in the cbindings yet. remove this comment when it is - */ #define GSS_S_GAP_TOKEN (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 4)) diff --git a/src/lib/gssapi/generic/gssapi_err_generic.et b/src/lib/gssapi/generic/gssapi_err_generic.et index ddeed4227..99ba45fe3 100644 --- a/src/lib/gssapi/generic/gssapi_err_generic.et +++ b/src/lib/gssapi/generic/gssapi_err_generic.et @@ -40,4 +40,7 @@ error_code G_BAD_HOSTNAME, "Hostname in SERVICE-NAME string could not be canonic error_code G_WRONG_MECH, "Mechanism is incorrect" error_code G_BAD_TOK_HEADER, "Token header is malformed or corrupt" error_code G_BAD_DIRECTION, "Packet was replayed in wrong direction" +error_code G_TOK_TRUNC, "Token is missing data" +error_code G_REFLECT, "Token was reflected" +error_code G_WRONG_TOKID, "Received token ID does not match expected token ID" end diff --git a/src/lib/gssapi/generic/util_token.c b/src/lib/gssapi/generic/util_token.c index 627b5011b..9e186a153 100644 --- a/src/lib/gssapi/generic/util_token.c +++ b/src/lib/gssapi/generic/util_token.c @@ -205,9 +205,12 @@ gss_int32 g_verify_token_header(mech, body_size, buf_in, tok_type, toksize) if ((toksize-=2) < 0) return(G_BAD_TOK_HEADER); + if (ret) + return(ret); + if ((*buf++ != ((tok_type>>8)&0xff)) || - (*buf++ != (tok_type&0xff))) - return(G_BAD_TOK_HEADER); + (*buf++ != (tok_type&0xff))) + return(G_WRONG_TOKID); if (!ret) { *buf_in = buf; diff --git a/src/lib/gssapi/krb5/ChangeLog b/src/lib/gssapi/krb5/ChangeLog index a94aeb72d..e12dfdb2b 100644 --- a/src/lib/gssapi/krb5/ChangeLog +++ b/src/lib/gssapi/krb5/ChangeLog @@ -1,3 +1,42 @@ +1998-10-27 Marc Horowitz <marc@mit.edu> + + * Makefile.in, accept_sec_context.c, acquire_cred.c, canon_name.c, + delete_sec_context.c, disp_status.c, gssapiP_krb5.h, + gssapi_err_krb5.et, gssapi_krb5.c, gssapi_krb5.h, + init_sec_context.c, inq_cred.c, inq_names.c, k5seal.c, k5unseal.c, + rel_oid.c, ser_sctx.c, util_cksum.c, util_crypt.c, util_seed.c, + util_seqnum.c, wrap_size_limit.c: convert to new crypto api. + Implement new krb5 v2 gssapi mechanism. + + * add_cred.c, util_ctxsetup.c: New files needed to implement the + krb5 v2 mech. + +Mon Sep 21 00:32:28 1998 Tom Yu <tlyu@mit.edu> + + * accept_sec_context.c (krb5_gss_accept_sec_context): Free authdat + even on success to avoid a memory leak. + + * util_cksum.c (kg_checksum_channel_bindings): Fix memory leak by + not allocating cksum->contents unless we have to return a + zero-filled one. + + * k5unseal.c (kg_unseal_v1): Fix memorly leak by not allocating + md5cksum.contents. + + * k5seal.c (make_seal_token_v1): Fix memory leak by not allocating + md5cksum.contents. + + * accept_sec_context.c (krb5_gss_accept_sec_context): Only free + ap_req.data if it was allocated by kg2_parse_token(), otherwise we + lose very badly trying to free the middle of a potentially + malloc()'ed block, possibly coredumping. + +Thu Sep 3 19:35:44 1998 Tom Yu <tlyu@mit.edu> + + * accept_sec_context.c (krb5_gss_accept_sec_context): Fix typo; + bash the enctype in ctx->subkey->enctype rather than just + "enctype", which nothing checks. + Fri Jul 24 21:13:53 1998 Tom Yu <tlyu@mit.edu> * wrap_size_limit.c (krb5_gss_wrap_size_limit): Fix to round down diff --git a/src/lib/gssapi/krb5/Makefile.in b/src/lib/gssapi/krb5/Makefile.in index 5b74b81d9..00b575c34 100644 --- a/src/lib/gssapi/krb5/Makefile.in +++ b/src/lib/gssapi/krb5/Makefile.in @@ -18,6 +18,7 @@ gssapi_err_krb5.c: gssapi_err_krb5.et SRCS = \ $(srcdir)/accept_sec_context.c \ $(srcdir)/acquire_cred.c \ + $(srcdir)/add_cred.c \ $(srcdir)/canon_name.c \ $(srcdir)/compare_name.c \ $(srcdir)/context_time.c \ @@ -50,6 +51,7 @@ SRCS = \ $(srcdir)/unseal.c \ $(srcdir)/util_cksum.c \ $(srcdir)/util_crypt.c \ + $(srcdir)/util_ctxsetup.c \ $(srcdir)/util_seed.c \ $(srcdir)/util_seqnum.c \ $(srcdir)/val_cred.c \ @@ -63,6 +65,7 @@ SRCS = \ OBJS = \ accept_sec_context.$(OBJEXT) \ acquire_cred.$(OBJEXT) \ + add_cred.$(OBJEXT) \ canon_name.$(OBJEXT) \ compare_name.$(OBJEXT) \ context_time.$(OBJEXT) \ @@ -95,6 +98,7 @@ OBJS = \ unseal.$(OBJEXT) \ util_cksum.$(OBJEXT) \ util_crypt.$(OBJEXT) \ + util_ctxsetup.$(OBJEXT) \ util_seed.$(OBJEXT) \ util_seqnum.$(OBJEXT) \ val_cred.$(OBJEXT) \ @@ -108,6 +112,7 @@ OBJS = \ STLIBOBJS = \ accept_sec_context.o \ acquire_cred.o \ + add_cred.o \ canon_name.o \ compare_name.o \ context_time.o \ @@ -140,6 +145,7 @@ STLIBOBJS = \ unseal.o \ util_cksum.o \ util_crypt.o \ + util_ctxsetup.o \ util_seed.o \ util_seqnum.o \ val_cred.o \ diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c index ee204d3e0..90e988ae0 100644 --- a/src/lib/gssapi/krb5/accept_sec_context.c +++ b/src/lib/gssapi/krb5/accept_sec_context.c @@ -20,6 +20,32 @@ * PERFORMANCE OF THIS SOFTWARE. */ +/* + * Copyright (C) 1998 by the FundsXpress, INC. + * + * All rights reserved. + * + * Export of this software from the United States of America may require + * a specific license from the United States Government. It is the + * responsibility of any person or organization contemplating export to + * obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of FundsXpress. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. FundsXpress makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + #include "k5-int.h" #include "gssapiP_krb5.h" #include <memory.h> @@ -58,9 +84,8 @@ rd_req_keyproc(krb5_pointer keyprocarg, krb5_principal server, /* Decode, decrypt and store the forwarded creds in the local ccache. */ static krb5_error_code -rd_and_store_for_creds(context, auth_context, inbuf, out_cred) +rd_and_store_for_creds(context, inbuf, out_cred) krb5_context context; - krb5_auth_context auth_context; krb5_data *inbuf; krb5_gss_cred_id_t *out_cred; { @@ -69,10 +94,16 @@ rd_and_store_for_creds(context, auth_context, inbuf, out_cred) krb5_ccache ccache; krb5_gss_cred_id_t cred = NULL; extern krb5_cc_ops krb5_mcc_ops; + krb5_auth_context auth_context = NULL; - if ((retval = krb5_rd_cred(context, auth_context, inbuf, &creds, NULL))) + if ((retval = krb5_auth_con_init(context, &auth_context))) return(retval); + krb5_auth_con_setflags(context, auth_context, 0); + + if ((retval = krb5_rd_cred(context, auth_context, inbuf, &creds, NULL))) + goto cleanup; + /* Lots of kludging going on here... Some day the ccache interface will be rewritten though */ @@ -91,47 +122,51 @@ rd_and_store_for_creds(context, auth_context, inbuf, out_cred) /* generate a delegated credential handle */ if (out_cred) { - /* allocate memory for a cred_t... */ - if (!(cred = - (krb5_gss_cred_id_t) xmalloc(sizeof(krb5_gss_cred_id_rec)))) { - retval = ENOMEM; /* out of memory? */ - goto cleanup; - } + /* allocate memory for a cred_t... */ + if (!(cred = + (krb5_gss_cred_id_t) xmalloc(sizeof(krb5_gss_cred_id_rec)))) { + retval = ENOMEM; /* out of memory? */ + goto cleanup; + } - /* zero it out... */ - memset(cred, 0, sizeof(krb5_gss_cred_id_rec)); + /* zero it out... */ + memset(cred, 0, sizeof(krb5_gss_cred_id_rec)); - /* copy the client principle into it... */ - if ((retval = - krb5_copy_principal(context, creds[0]->client, &(cred->princ)))) { - retval = ENOMEM; /* out of memory? */ - xfree(cred); /* clean up memory on failure */ - cred = NULL; - goto cleanup; - } - - cred->usage = GSS_C_INITIATE; /* we can't accept with this */ - /* cred->princ already set */ - cred->actual_mechs = gss_mech_set_krb5_both; /* both mechs work */ - cred->prerfc_mech = cred->rfc_mech = 1; /* Ibid. */ - cred->keytab = NULL; /* no keytab associated with this... */ - cred->ccache = ccache; /* but there is a credential cache */ - cred->tgt_expire = creds[0]->times.endtime; /* store the end time */ + /* copy the client principle into it... */ + if ((retval = + krb5_copy_principal(context, creds[0]->client, &(cred->princ)))) { + retval = ENOMEM; /* out of memory? */ + xfree(cred); /* clean up memory on failure */ + cred = NULL; + goto cleanup; + } + + cred->usage = GSS_C_INITIATE; /* we can't accept with this */ + /* cred->princ already set */ + cred->prerfc_mech = 1; /* this cred will work with all three mechs */ + cred->rfc_mech = 1; + cred->rfcv2_mech = 1; + cred->keytab = NULL; /* no keytab associated with this... */ + cred->ccache = ccache; /* but there is a credential cache */ + cred->tgt_expire = creds[0]->times.endtime; /* store the end time */ } /* If there were errors, there might have been a memory leak - if (!cred) - if ((retval = krb5_cc_close(context, ccache))) - goto cleanup; - */ + if (!cred) + if ((retval = krb5_cc_close(context, ccache))) + goto cleanup; + */ cleanup: krb5_free_tgt_creds(context, creds); if (!cred && ccache) - (void)krb5_cc_close(context, ccache); + (void)krb5_cc_close(context, ccache); if (out_cred) - *out_cred = cred; /* return credential */ + *out_cred = cred; /* return credential */ + + if (auth_context) + krb5_auth_con_free(context, auth_context); return retval; } @@ -158,16 +193,17 @@ krb5_gss_accept_sec_context(minor_status, context_handle, unsigned char *ptr, *ptr2; char *sptr; long tmp; + size_t md5len; int bigend; krb5_gss_cred_id_t cred = 0; - krb5_data ap_req; + krb5_data ap_rep, ap_req, mic; int i; krb5_error_code code; krb5_address addr, *paddr; krb5_authenticator *authdat = 0; - krb5_checksum md5; + krb5_checksum reqcksum; krb5_principal name = NULL; - int gss_flags = 0; + krb5_ui_4 gss_flags = 0; int decode_req_message = 0; krb5_gss_ctx_id_rec *ctx = 0; krb5_enctype enctype; @@ -177,14 +213,18 @@ krb5_gss_accept_sec_context(minor_status, context_handle, krb5_auth_context auth_context = NULL; krb5_ticket * ticket = NULL; int option_id; - krb5_data option; - krb5_auth_context auth_context_cred = NULL; + krb5_data option, cksumdata; const gss_OID_desc *mech_used = NULL; OM_uint32 major_status = GSS_S_FAILURE; krb5_error krb_error_data; krb5_data scratch; gss_cred_id_t cred_handle = NULL; krb5_gss_cred_id_t deleg_cred = NULL; + int token_length; + int gsskrb5_vers; + int nctypes; + krb5_cksumtype *ctypes; + struct kg2_option fwcred; if (GSS_ERROR(kg_get_context(minor_status, &context))) return(GSS_S_FAILURE); @@ -196,7 +236,11 @@ krb5_gss_accept_sec_context(minor_status, context_handle, output_token->length = 0; output_token->value = NULL; token.value = 0; - md5.contents = 0; + reqcksum.contents = 0; + mic.data = 0; + ap_req.data = 0; + ap_rep.data = 0; + cksumdata.data = 0; if (mech_type) *mech_type = GSS_C_NULL_OID; @@ -217,18 +261,19 @@ krb5_gss_accept_sec_context(minor_status, context_handle, /* handle default cred handle */ if (verifier_cred_handle == GSS_C_NO_CREDENTIAL) { - major_status = krb5_gss_acquire_cred(&code, GSS_C_NO_NAME, - GSS_C_INDEFINITE, GSS_C_NO_OID_SET, - GSS_C_ACCEPT, &cred_handle, - NULL, NULL); - if (major_status != GSS_S_COMPLETE) - goto fail; - } else - cred_handle = verifier_cred_handle; + major_status = krb5_gss_acquire_cred(&code, GSS_C_NO_NAME, + GSS_C_INDEFINITE, GSS_C_NO_OID_SET, + GSS_C_ACCEPT, &cred_handle, + NULL, NULL); + if (major_status != GSS_S_COMPLETE) + goto fail; + } else { + cred_handle = verifier_cred_handle; + } - major_status = krb5_gss_validate_cred(minor_status, verifier_cred_handle); + major_status = krb5_gss_validate_cred(&code, verifier_cred_handle); if (GSS_ERROR(major_status)) - goto fail; + goto fail; cred = (krb5_gss_cred_id_t) cred_handle; @@ -236,9 +281,9 @@ krb5_gss_accept_sec_context(minor_status, context_handle, if ((cred->usage != GSS_C_ACCEPT) && (cred->usage != GSS_C_BOTH)) { - code = 0; - major_status = GSS_S_NO_CRED; - goto fail; + code = 0; + major_status = GSS_S_NO_CRED; + goto fail; } /* verify the token's integrity, and leave the token in ap_req. @@ -246,60 +291,92 @@ krb5_gss_accept_sec_context(minor_status, context_handle, ptr = (unsigned char *) input_token->value; - if ((err = g_verify_token_header((gss_OID) gss_mech_krb5, &(ap_req.length), - &ptr, KG_TOK_CTX_AP_REQ, - input_token->length))) { - /* - * Previous versions of this library used the old mech_id - * and some broken behavior (wrong IV on checksum - * encryption). We support the old mech_id for - * compatibility, and use it to decide when to use the - * old behavior. - */ - if (err != G_WRONG_MECH || - (code = g_verify_token_header((gss_OID) gss_mech_krb5_old, - &(ap_req.length), - &ptr, KG_TOK_CTX_AP_REQ, - input_token->length))) { - major_status = GSS_S_DEFECTIVE_TOKEN; - goto fail; - } else { -#if 0 /* Don't restrict mechanisms when accepting contexts */ - if (! cred->prerfc_mech) { - code = G_WRONG_MECH; - major_status = GSS_S_DEFECTIVE_TOKEN; - goto fail; - } -#endif - mech_used = gss_mech_krb5_old; - } + if (!(code = g_verify_token_header((gss_OID) gss_mech_krb5, + &(ap_req.length), + &ptr, KG_TOK_CTX_AP_REQ, + input_token->length))) { + if (! cred->rfc_mech) { + code = G_WRONG_MECH; + major_status = GSS_S_DEFECTIVE_TOKEN; + goto fail; + } + mech_used = gss_mech_krb5; + gsskrb5_vers = 1000; + } else if ((code == G_WRONG_MECH) && + !(code = g_verify_token_header((gss_OID) gss_mech_krb5_old, + &(ap_req.length), + &ptr, KG_TOK_CTX_AP_REQ, + input_token->length))) { + /* + * Previous versions of this library used the old mech_id + * and some broken behavior (wrong IV on checksum + * encryption). We support the old mech_id for + * compatibility, and use it to decide when to use the + * old behavior. + */ + if (! cred->prerfc_mech) { + code = G_WRONG_MECH; + major_status = GSS_S_DEFECTIVE_TOKEN; + goto fail; + } + mech_used = gss_mech_krb5_old; + gsskrb5_vers = 1000; + } else if ((code == G_WRONG_MECH) && + !(code = g_verify_token_header((gss_OID) gss_mech_krb5_v2, + &token_length, + &ptr, KG2_TOK_INITIAL, + input_token->length))) { + if (! cred->rfcv2_mech) { + code = G_WRONG_MECH; + major_status = GSS_S_DEFECTIVE_TOKEN; + goto fail; + } + mech_used = gss_mech_krb5_v2; + gsskrb5_vers = 2000; } else { -#if 0 /* Don't restrict mechanisms when accepting contexts */ - if (! cred->rfc_mech) { - code = G_WRONG_MECH; - major_status = GSS_S_DEFECTIVE_TOKEN; - goto fail; - } -#endif - mech_used = gss_mech_krb5; + major_status = GSS_S_DEFECTIVE_TOKEN; + goto fail; } - sptr = (char *) ptr; - TREAD_STR(sptr, ap_req.data, ap_req.length); - decode_req_message = 1; + if (gsskrb5_vers == 2000) { + /* gss krb5 v2 */ + + fwcred.option_id = KRB5_GSS_FOR_CREDS_OPTION; + fwcred.data = NULL; + + if (GSS_ERROR(major_status = + kg2_parse_token(&code, ptr, token_length, + &gss_flags, &nctypes, &ctypes, + delegated_cred_handle?1:0, + &fwcred, &ap_req, NULL))) { + goto fail; + } + + gss_flags = (ptr[0]<<24) | (ptr[1]<<16) | (ptr[2]<<8) | ptr[3]; + + gss_flags &= ~GSS_C_DELEG_FLAG; /* mask out the delegation flag; + if there's a delegation, we'll + set it below */ + } else { + /* gss krb5 v1 */ + + sptr = (char *) ptr; + TREAD_STR(sptr, ap_req.data, ap_req.length); + decode_req_message = 1; + } /* construct the sender_addr */ if ((input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) && (input_chan_bindings->initiator_addrtype == GSS_C_AF_INET)) { - /* XXX is this right? */ - addr.addrtype = ADDRTYPE_INET; - addr.length = input_chan_bindings->initiator_address.length; - addr.contents = input_chan_bindings->initiator_address.value; + /* XXX is this right? */ + addr.addrtype = ADDRTYPE_INET; + addr.length = input_chan_bindings->initiator_address.length; + addr.contents = input_chan_bindings->initiator_address.value; - paddr = &addr; + paddr = &addr; } else { - paddr = NULL; + paddr = NULL; } /* decode the AP_REQ message */ @@ -307,13 +384,18 @@ krb5_gss_accept_sec_context(minor_status, context_handle, /* decode the message */ if ((code = krb5_auth_con_init(context, &auth_context))) { - *minor_status = code; - return(GSS_S_FAILURE); + major_status = GSS_S_FAILURE; + goto fail; } if ((code = krb5_auth_con_setrcache(context, auth_context, cred->rcache))) { - *minor_status = code; - return(GSS_S_FAILURE); + major_status = GSS_S_FAILURE; + goto fail; } + if ((code = krb5_auth_con_setaddrs(context, auth_context, NULL, paddr))) { + major_status = GSS_S_FAILURE; + goto fail; + } + if ((code = krb5_rd_req(context, &auth_context, &ap_req, cred->princ, cred->keytab, NULL, &ticket))) { major_status = GSS_S_FAILURE; @@ -328,137 +410,142 @@ krb5_gss_accept_sec_context(minor_status, context_handle, if ((authdat->authenticator->subkey == NULL) || (authdat->ticket->enc_part2 == NULL)) { code = KG_NO_SUBKEY; + major_status = GSS_S_FAILURE; goto fail; } #endif - /* verify that the checksum is correct */ + if (gsskrb5_vers == 2000) { + bigend = 1; + } else { + /* gss krb5 v1 */ - /* - The checksum may be either exactly 24 bytes, in which case - no options are specified, or greater than 24 bytes, in which case - one or more options are specified. Currently, the only valid - option is KRB5_GSS_FOR_CREDS_OPTION ( = 1 ). - */ - - if ((authdat->checksum->checksum_type != CKSUMTYPE_KG_CB) || - (authdat->checksum->length < 24)) { - code = 0; - major_status = GSS_S_BAD_BINDINGS; + /* stash this now, for later. */ + if (code = krb5_c_checksum_length(context, CKSUMTYPE_RSA_MD5, + &md5len)) { + major_status = GSS_S_FAILURE; goto fail; - } + } - /* - "Be liberal in what you accept, and - conservative in what you send" - -- rfc1123 + /* verify that the checksum is correct */ - This code will let this acceptor interoperate with an initiator - using little-endian or big-endian integer encoding. - */ + /* + The checksum may be either exactly 24 bytes, in which case + no options are specified, or greater than 24 bytes, in which case + one or more options are specified. Currently, the only valid + option is KRB5_GSS_FOR_CREDS_OPTION ( = 1 ). + */ + + if ((authdat->checksum->checksum_type != CKSUMTYPE_KG_CB) || + (authdat->checksum->length < 24)) { + code = 0; + major_status = GSS_S_BAD_BINDINGS; + goto fail; + } - ptr = (unsigned char *) authdat->checksum->contents; - bigend = 0; + /* + "Be liberal in what you accept, and + conservative in what you send" + -- rfc1123 - TREAD_INT(ptr, tmp, bigend); + This code will let this acceptor interoperate with an initiator + using little-endian or big-endian integer encoding. + */ - if (tmp != krb5_checksum_size(context, CKSUMTYPE_RSA_MD5)) { ptr = (unsigned char *) authdat->checksum->contents; - bigend = 1; + bigend = 0; TREAD_INT(ptr, tmp, bigend); - if (tmp != krb5_checksum_size(context, CKSUMTYPE_RSA_MD5)) { - major_status = GSS_S_FAILURE; - code = KG_BAD_LENGTH; - goto fail; + if (tmp != md5len) { + ptr = (unsigned char *) authdat->checksum->contents; + bigend = 1; + + TREAD_INT(ptr, tmp, bigend); + + if (tmp != md5len) { + code = KG_BAD_LENGTH; + major_status = GSS_S_FAILURE; + goto fail; + } } - } - /* at this point, bigend is set according to the initiator's byte order */ + /* at this point, bigend is set according to the initiator's + byte order */ - if ((code = kg_checksum_channel_bindings(context, input_chan_bindings, &md5, - bigend))) { - major_status = GSS_S_BAD_BINDINGS; - goto fail; - } + if ((code = kg_checksum_channel_bindings(context, input_chan_bindings, + &reqcksum, bigend))) { + major_status = GSS_S_BAD_BINDINGS; + goto fail; + } - TREAD_STR(ptr, ptr2, md5.length); - if (memcmp(ptr2, md5.contents, md5.length) != 0) { + TREAD_STR(ptr, ptr2, reqcksum.length); + if (memcmp(ptr2, reqcksum.contents, reqcksum.length) != 0) { code = 0; major_status = GSS_S_BAD_BINDINGS; goto fail; - } - - xfree(md5.contents); - md5.contents = 0; - - TREAD_INT(ptr, gss_flags, bigend); - gss_flags &= ~GSS_C_DELEG_FLAG; /* mask out the delegation flag; if there's - a delegation, we'll set it below */ - decode_req_message = 0; - - /* if the checksum length > 24, there are options to process */ + } - if(authdat->checksum->length > 24) { + xfree(reqcksum.contents); + reqcksum.contents = 0; - i = authdat->checksum->length - 24; + TREAD_INT(ptr, gss_flags, bigend); + gss_flags &= ~GSS_C_DELEG_FLAG; /* mask out the delegation flag; if + there's a delegation, we'll set + it below */ + decode_req_message = 0; - while(i>0) { + /* if the checksum length > 24, there are options to process */ - TREAD_INT16(ptr, option_id, bigend); + if(authdat->checksum->length > 24) { - switch(option_id) { + i = authdat->checksum->length - 24; - case KRB5_GSS_FOR_CREDS_OPTION: + while(i>0) { - TREAD_INT16(ptr, option.length, bigend); + TREAD_INT16(ptr, option_id, bigend); - /* have to use ptr2, since option.data is wrong type and - macro uses ptr as both lvalue and rvalue */ + switch(option_id) { - TREAD_STR(ptr, ptr2, bigend); - option.data = (char FAR *) ptr2; + case KRB5_GSS_FOR_CREDS_OPTION: - /* get a temporary auth_context structure for the - call to rd_and_store_for_creds() and clear its flags */ + TREAD_INT16(ptr, option.length, bigend); - if ((code = krb5_auth_con_init(context, - &auth_context_cred))) { - major_status = GSS_S_FAILURE; - goto fail; - } + /* have to use ptr2, since option.data is wrong type and + macro uses ptr as both lvalue and rvalue */ - krb5_auth_con_setflags(context, auth_context_cred, 0); + TREAD_STR(ptr, ptr2, bigend); + option.data = (char FAR *) ptr2; - /* store the delegated credential */ + /* store the delegated credential */ - rd_and_store_for_creds(context, auth_context_cred, - &option, - (delegated_cred_handle) ? - &deleg_cred : NULL); + if (code = rd_and_store_for_creds(context, &option, + (delegated_cred_handle) ? + &deleg_cred : NULL)) { + major_status = GSS_S_FAILURE; + goto fail; + } - i -= option.length + 4; + i -= option.length + 4; - krb5_auth_con_free(context, auth_context_cred); + gss_flags |= GSS_C_DELEG_FLAG; /* got a delegation */ - gss_flags |= GSS_C_DELEG_FLAG; /* got a delegation */ + break; - break; + /* default: */ + /* unknown options aren't an error */ - /* default: */ - /* unknown options aren't an error */ + } /* switch */ + } /* while */ + } /* if */ + } - } /* switch */ - } /* while */ - } /* if */ - /* create the ctx struct and start filling it in */ if ((ctx = (krb5_gss_ctx_id_rec *) xmalloc(sizeof(krb5_gss_ctx_id_rec))) == NULL) { - major_status = GSS_S_FAILURE; code = ENOMEM; + major_status = GSS_S_FAILURE; goto fail; } @@ -469,83 +556,177 @@ krb5_gss_accept_sec_context(minor_status, context_handle, ctx->gss_flags = KG_IMPLFLAGS(gss_flags); ctx->seed_init = 0; ctx->big_endian = bigend; - - major_status = GSS_S_FAILURE; + ctx->gsskrb5_version = gsskrb5_vers; /* Intern the ctx pointer so that delete_sec_context works */ if (! kg_save_ctx_id((gss_ctx_id_t) ctx)) { - code = G_VALIDATE_FAILED; - xfree(ctx); - ctx = 0; - goto fail; + xfree(ctx); + ctx = 0; + + code = G_VALIDATE_FAILED; + major_status = GSS_S_FAILURE; + goto fail; } - - if ((code = krb5_copy_principal(context, cred->princ, &ctx->here))) - goto fail; - if ((code = krb5_copy_principal(context, authdat->client, &ctx->there))) - goto fail; + if ((code = krb5_copy_principal(context, cred->princ, &ctx->here))) { + major_status = GSS_S_FAILURE; + goto fail; + } - /* done with authdat */ - krb5_free_authenticator(context, authdat); - authdat = 0; + if ((code = krb5_copy_principal(context, authdat->client, &ctx->there))) { + major_status = GSS_S_FAILURE; + goto fail; + } if ((code = krb5_auth_con_getremotesubkey(context, auth_context, - &ctx->subkey))) - goto fail; + &ctx->subkey))) { + major_status = GSS_S_FAILURE; + goto fail; + } /* use the session key if the subkey isn't present */ if (ctx->subkey == NULL) { if ((code = krb5_auth_con_getkey(context, auth_context, - &ctx->subkey))) - goto fail; + &ctx->subkey))) { + major_status = GSS_S_FAILURE; + goto fail; + } } if (ctx->subkey == NULL) { /* this isn't a very good error, but it's not clear to me this can actually happen */ + major_status = GSS_S_FAILURE; code = KRB5KDC_ERR_NULL_KEY; goto fail; } - switch(ctx->subkey->enctype) { - case ENCTYPE_DES_CBC_MD5: - case ENCTYPE_DES_CBC_CRC: - enctype = ENCTYPE_DES_CBC_RAW; - ctx->signalg = 0; - ctx->cksum_size = 8; - ctx->sealalg = 0; - break; + if (gsskrb5_vers == 2000) { + int cblen; + krb5_boolean valid; + + /* intersect the token ctypes with the local ctypes */ + + if (code = krb5_c_keyed_checksum_types(context, ctx->subkey->enctype, + &ctx->nctypes, &ctx->ctypes)) + goto fail; + + if (nctypes == 0) { + code = KRB5_CRYPTO_INTERNAL; + goto fail; + } + + kg2_intersect_ctypes(&ctx->nctypes, ctx->ctypes, nctypes, ctypes); + + if (nctypes == 0) { + code = KG_NO_CTYPES; + goto fail; + } + + /* process the delegated cred, if any */ + + if (fwcred.data) { + krb5_data option; + + option.length = fwcred.length; + option.data = fwcred.data; + + if (code = rd_and_store_for_creds(context, &option, &deleg_cred)) { + major_status = GSS_S_FAILURE; + goto fail; + } + + gss_flags |= GSS_C_DELEG_FLAG; /* got a delegation */ + } + + /* construct the checksum buffer */ + + cblen = 4*5; + if (input_chan_bindings) + cblen += (input_chan_bindings->initiator_address.length+ + input_chan_bindings->acceptor_address.length+ + input_chan_bindings->application_data.length); + + cksumdata.length = cblen + ((char *)(ap_req.data-2) - (char *)(ptr-2)); + + if ((cksumdata.data = (char *) malloc(cksumdata.length)) == NULL) { + code = ENOMEM; + major_status = GSS_S_FAILURE; + goto fail; + } + + ptr2 = cksumdata.data; + + if (input_chan_bindings) { + TWRITE_INT(ptr2, input_chan_bindings->initiator_addrtype, 1); + TWRITE_BUF(ptr2, input_chan_bindings->initiator_address, 1); + TWRITE_INT(ptr2, input_chan_bindings->acceptor_addrtype, 1); + TWRITE_BUF(ptr2, input_chan_bindings->acceptor_address, 1); + TWRITE_BUF(ptr2, input_chan_bindings->application_data, 1); + } else { + memset(ptr2, 0, cblen); + ptr2 += cblen; + } + + memcpy(ptr2, ptr-2, ((char *)(ap_req.data-2) - (char *)(ptr-2))); + + if (code = krb5_c_verify_checksum(context, ctx->subkey, + KRB5_KEYUSAGE_AP_REQ_AUTH_CKSUM, + &cksumdata, authdat->checksum, + &valid)) { + major_status = GSS_S_FAILURE; + goto fail; + } + + free(cksumdata.data); + cksumdata.data = 0; + + if (!valid) { + code = 0; + major_status = GSS_S_BAD_SIG; + goto fail; + } + } else { + /* gss krb5 v1 */ + + switch(ctx->subkey->enctype) { + case ENCTYPE_DES_CBC_MD5: + case ENCTYPE_DES_CBC_CRC: + ctx->subkey->enctype = ENCTYPE_DES_CBC_RAW; + ctx->signalg = 0; + ctx->cksum_size = 8; + ctx->sealalg = 0; + break; #if 0 - case ENCTYPE_DES3_CBC_MD5: - enctype = ENCTYPE_DES3_CBC_RAW; - ctx->signalg = 3; - ctx->cksum_size = 16; - ctx->sealalg = 1; - break; + case ENCTYPE_DES3_CBC_MD5: + enctype = ENCTYPE_DES3_CBC_RAW; + ctx->signalg = 3; + ctx->cksum_size = 16; + ctx->sealalg = 1; + break; #endif - default: - code = KRB5_BAD_ENCTYPE; - goto fail; - } - - /* fill in the encryption descriptors */ + default: + code = KRB5_BAD_ENCTYPE; + goto fail; + } - krb5_use_enctype(context, &ctx->enc.eblock, enctype); - ctx->enc.processed = 0; + /* fill in the encryption descriptors */ - if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc.key))) + if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc))) { + major_status = GSS_S_FAILURE; goto fail; + } - for (i=0; i<ctx->enc.key->length; i++) - /*SUPPRESS 113*/ - ctx->enc.key->contents[i] ^= 0xf0; + for (i=0; i<ctx->enc->length; i++) + /*SUPPRESS 113*/ + ctx->enc->contents[i] ^= 0xf0; - krb5_use_enctype(context, &ctx->seq.eblock, enctype); - ctx->seq.processed = 0; - if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->seq.key))) + if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->seq))) { + major_status = GSS_S_FAILURE; goto fail; + } + } ctx->endtime = ticket->enc_part2->times.endtime; ctx->krb_flags = ticket->enc_part2->flags; @@ -554,13 +735,15 @@ krb5_gss_accept_sec_context(minor_status, context_handle, krb5_auth_con_getremoteseqnumber(context, auth_context, &ctx->seq_recv); - if ((code = krb5_timeofday(context, &now))) - goto fail; + if ((code = krb5_timeofday(context, &now))) { + major_status = GSS_S_FAILURE; + goto fail; + } if (ctx->endtime < now) { - code = 0; - major_status = GSS_S_CREDENTIALS_EXPIRED; - goto fail; + code = 0; + major_status = GSS_S_CREDENTIALS_EXPIRED; + goto fail; } g_order_init(&(ctx->seqstate), ctx->seq_recv, @@ -573,40 +756,156 @@ krb5_gss_accept_sec_context(minor_status, context_handle, /* generate an AP_REP if necessary */ if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) { - krb5_data ap_rep; - unsigned char * ptr; - if ((code = krb5_mk_rep(context, auth_context, &ap_rep))) - goto fail; - - krb5_auth_con_getlocalseqnumber(context, auth_context, &ctx->seq_send); - token.length = g_token_size((gss_OID) mech_used, ap_rep.length); - - if ((token.value = (unsigned char *) xmalloc(token.length)) == NULL) { - code = ENOMEM; - goto fail; - } - ptr = token.value; - g_make_token_header((gss_OID) mech_used, ap_rep.length, - &ptr, KG_TOK_CTX_AP_REP); - - TWRITE_STR(ptr, ap_rep.data, ap_rep.length); - xfree(ap_rep.data); + unsigned char * ptr; + if ((code = krb5_mk_rep(context, auth_context, &ap_rep))) { + major_status = GSS_S_FAILURE; + goto fail; + } + + krb5_auth_con_getlocalseqnumber(context, auth_context, + &ctx->seq_send); + + /* the reply token hasn't been sent yet, but that's ok. */ + ctx->established = 1; + + if (ctx->gsskrb5_version == 2000) { + krb5_ui_4 tok_flags; + + tok_flags = + (ctx->gss_flags & GSS_C_DELEG_FLAG)?KG2_RESP_FLAG_DELEG_OK:0; + + cksumdata.length = 8 + 4*ctx->nctypes + 4; + + if ((cksumdata.data = (char *) malloc(cksumdata.length)) == NULL) { + code = ENOMEM; + major_status = GSS_S_FAILURE; + goto fail; + } + + /* construct the token fields */ + + ptr = cksumdata.data; + + ptr[0] = (KG2_TOK_RESPONSE >> 8) & 0xff; + ptr[1] = KG2_TOK_RESPONSE & 0xff; + + ptr[2] = (tok_flags >> 24) & 0xff; + ptr[3] = (tok_flags >> 16) & 0xff; + ptr[4] = (tok_flags >> 8) & 0xff; + ptr[5] = tok_flags & 0xff; + + ptr[6] = (ctx->nctypes >> 8) & 0xff; + ptr[7] = ctx->nctypes & 0xff; + + ptr += 8; + + for (i=0; i<ctx->nctypes; i++) { + ptr[i] = (ctx->ctypes[i] >> 24) & 0xff; + ptr[i+1] = (ctx->ctypes[i] >> 16) & 0xff; + ptr[i+2] = (ctx->ctypes[i] >> 8) & 0xff; + ptr[i+3] = ctx->ctypes[i] & 0xff; + + ptr += 4; + } + + memset(ptr, 0, 4); + + /* make the MIC token */ + + { + gss_buffer_desc text, token; + + text.length = cksumdata.length; + text.value = cksumdata.data; + + /* ctx->seq_send must be set before this call */ + + if (GSS_ERROR(major_status = + krb5_gss_get_mic(&code, ctx, + GSS_C_QOP_DEFAULT, + &text, &token))) + goto fail; + + mic.length = token.length; + mic.data = token.value; + } + + token.length = g_token_size((gss_OID) mech_used, + (cksumdata.length-2)+4+ap_rep.length+ + mic.length); + + if ((token.value = (unsigned char *) xmalloc(token.length)) + == NULL) { + code = ENOMEM; + major_status = GSS_S_FAILURE; + goto fail; + } + ptr = token.value; + g_make_token_header((gss_OID) mech_used, + (cksumdata.length-2)+4+ap_rep.length+mic.length, + &ptr, KG2_TOK_RESPONSE); + + memcpy(ptr, cksumdata.data+2, cksumdata.length-2); + ptr += cksumdata.length-2; + + ptr[0] = (ap_rep.length >> 8) & 0xff; + ptr[1] = ap_rep.length & 0xff; + memcpy(ptr+2, ap_rep.data, ap_rep.length); + + ptr += (2+ap_rep.length); + + ptr[0] = (mic.length >> 8) & 0xff; + ptr[1] = mic.length & 0xff; + memcpy(ptr+2, mic.data, mic.length); + + ptr += (2+mic.length); + + free(cksumdata.data); + cksumdata.data = 0; + + /* gss krb5 v2 */ + } else { + /* gss krb5 v1 */ + + token.length = g_token_size((gss_OID) mech_used, ap_rep.length); + + if ((token.value = (unsigned char *) xmalloc(token.length)) + == NULL) { + major_status = GSS_S_FAILURE; + code = ENOMEM; + goto fail; + } + ptr = token.value; + g_make_token_header((gss_OID) mech_used, ap_rep.length, + &ptr, KG_TOK_CTX_AP_REP); + + TWRITE_STR(ptr, ap_rep.data, ap_rep.length); + xfree(ap_rep.data); + + ctx->established = 1; + + } } else { - token.length = 0; - token.value = NULL; - ctx->seq_send = ctx->seq_recv; + token.length = 0; + token.value = NULL; + ctx->seq_send = ctx->seq_recv; + + ctx->established = 1; } /* set the return arguments */ if (src_name) { - if ((code = krb5_copy_principal(context, ctx->there, &name))) - goto fail; - /* intern the src_name */ - if (! kg_save_name((gss_name_t) name)) { - code = G_VALIDATE_FAILED; - goto fail; - } + if ((code = krb5_copy_principal(context, ctx->there, &name))) { + major_status = GSS_S_FAILURE; + goto fail; + } + /* intern the src_name */ + if (! kg_save_name((gss_name_t) name)) { + code = G_VALIDATE_FAILED; + major_status = GSS_S_FAILURE; + goto fail; + } } if (mech_type) @@ -618,7 +917,6 @@ krb5_gss_accept_sec_context(minor_status, context_handle, if (ret_flags) *ret_flags = ctx->gss_flags; - ctx->established = 1; *context_handle = ctx; *output_token = token; @@ -626,39 +924,54 @@ krb5_gss_accept_sec_context(minor_status, context_handle, *src_name = (gss_name_t) name; if (delegated_cred_handle && deleg_cred) { - if (!kg_save_cred_id((gss_cred_id_t) deleg_cred)) { - code = G_VALIDATE_FAILED; - goto fail; - } + if (!kg_save_cred_id((gss_cred_id_t) deleg_cred)) { + major_status = GSS_S_FAILURE; + code = G_VALIDATE_FAILED; + goto fail; + } - *delegated_cred_handle = (gss_cred_id_t) deleg_cred; + *delegated_cred_handle = (gss_cred_id_t) deleg_cred; } /* finally! */ *minor_status = 0; - return(GSS_S_COMPLETE); + major_status = GSS_S_COMPLETE; -fail: + fail: + if (ctypes) + free(ctypes); if (authdat) - krb5_free_authenticator(context, authdat); + krb5_free_authenticator(context, authdat); + if (reqcksum.contents) + xfree(reqcksum.contents); + if (ap_rep.data) + xfree(ap_rep.data); + if (mic.data) + xfree(mic.data); + if (cksumdata.data) + xfree(cksumdata.data); + + if (!GSS_ERROR(major_status)) + return(major_status); + + /* from here on is the real "fail" code */ + if (ctx) - (void) krb5_gss_delete_sec_context(minor_status, - (gss_ctx_id_t *) &ctx, NULL); + (void) krb5_gss_delete_sec_context(minor_status, + (gss_ctx_id_t *) &ctx, NULL); + if (deleg_cred) { /* free memory associated with the deleg credential */ + if (deleg_cred->ccache) + (void)krb5_cc_close(context, deleg_cred->ccache); + if (deleg_cred->princ) + krb5_free_principal(context, deleg_cred->princ); + xfree(deleg_cred); + } if (token.value) - xfree(token.value); + xfree(token.value); if (name) { - (void) kg_delete_name((gss_name_t) name); - krb5_free_principal(context, name); - } - if (md5.contents) - xfree(md5.contents); - if (deleg_cred) { /* free memory associated with the deleg credential */ - if (deleg_cred->ccache) - (void)krb5_cc_close(context, deleg_cred->ccache); - if (deleg_cred->princ) - krb5_free_principal(context, deleg_cred->princ); - xfree(deleg_cred); + (void) kg_delete_name((gss_name_t) name); + krb5_free_principal(context, name); } *minor_status = code; @@ -670,48 +983,75 @@ fail: * decode the authenticator to read out the gss_flags field. */ if (decode_req_message) { - krb5_ap_req * request; + krb5_ap_req * request; - if (decode_krb5_ap_req(&ap_req, &request)) - return (major_status); - if (request->ap_options & AP_OPTS_MUTUAL_REQUIRED) - gss_flags |= GSS_C_MUTUAL_FLAG; - krb5_free_ap_req(context, request); + if (decode_krb5_ap_req(&ap_req, &request)) + return (major_status); + if (request->ap_options & AP_OPTS_MUTUAL_REQUIRED) + gss_flags |= GSS_C_MUTUAL_FLAG; + krb5_free_ap_req(context, request); } if (cred && (gss_flags & GSS_C_MUTUAL_FLAG)) { - /* - * The client is expecting a response, so we can send an - * error token back - */ - memset(&krb_error_data, 0, sizeof(krb_error_data)); - - code -= ERROR_TABLE_BASE_krb5; - if (code < 0 || code > 128) - code = 60 /* KRB_ERR_GENERIC */; - - krb_error_data.error = code; - (void) krb5_us_timeofday(context, &krb_error_data.stime, - &krb_error_data.susec); - krb_error_data.server = cred->princ; + int tmsglen, toktype; + + /* + * The client is expecting a response, so we can send an + * error token back + */ + memset(&krb_error_data, 0, sizeof(krb_error_data)); + + code -= ERROR_TABLE_BASE_krb5; + if (code < 0 || code > 128) + code = 60 /* KRB_ERR_GENERIC */; + + krb_error_data.error = code; + (void) krb5_us_timeofday(context, &krb_error_data.stime, + &krb_error_data.susec); + krb_error_data.server = cred->princ; - code = krb5_mk_error(context, &krb_error_data, &scratch); - if (code) - return (major_status); + code = krb5_mk_error(context, &krb_error_data, &scratch); + if (code) + return (major_status); + + if (gsskrb5_vers == 2000) { + tmsglen = 12+scratch.length; + toktype = KG2_TOK_RESPONSE; + } else { + tmsglen = scratch.length; + toktype = KG_TOK_CTX_ERROR; + } - token.length = g_token_size((gss_OID) mech_used, scratch.length); - token.value = (unsigned char *) xmalloc(token.length); - if (!token.value) - return (major_status); + token.length = g_token_size((gss_OID) mech_used, tmsglen); + token.value = (unsigned char *) xmalloc(token.length); + if (!token.value) + return (major_status); - ptr = token.value; - g_make_token_header((gss_OID) mech_used, scratch.length, - &ptr, KG_TOK_CTX_ERROR); + ptr = token.value; + g_make_token_header((gss_OID) mech_used, tmsglen, &ptr, toktype); + + if (gsskrb5_vers == 2000) { + krb5_ui_4 flags; + + flags = KG2_RESP_FLAG_ERROR; + + ptr[0] = (flags << 24) & 0xff; + ptr[1] = (flags << 16) & 0xff; + ptr[2] = (flags << 8) & 0xff; + ptr[3] = flags & 0xff; + + memset(ptr+4, 0, 6); + + ptr[10] = (scratch.length << 8) & 0xff; + ptr[11] = scratch.length & 0xff; + + ptr += 12; + } - TWRITE_STR(ptr, scratch.data, scratch.length); - xfree(scratch.data); + TWRITE_STR(ptr, scratch.data, scratch.length); + xfree(scratch.data); - *output_token = token; + *output_token = token; } if (!verifier_cred_handle && cred_handle) { krb5_gss_release_cred(&code, cred_handle); diff --git a/src/lib/gssapi/krb5/acquire_cred.c b/src/lib/gssapi/krb5/acquire_cred.c index 1ca1bf31a..f968b7d4f 100644 --- a/src/lib/gssapi/krb5/acquire_cred.c +++ b/src/lib/gssapi/krb5/acquire_cred.c @@ -20,6 +20,32 @@ * PERFORMANCE OF THIS SOFTWARE. */ +/* + * Copyright (C) 1998 by the FundsXpress, INC. + * + * All rights reserved. + * + * Export of this software from the United States of America may require + * a specific license from the United States Government. It is the + * responsibility of any person or organization contemplating export to + * obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of FundsXpress. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. FundsXpress makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + #include "gssapiP_krb5.h" #ifdef HAVE_STRING_H #include <string.h> @@ -248,8 +274,7 @@ krb5_gss_acquire_cred(minor_status, desired_name, time_req, size_t i; krb5_gss_cred_id_t cred; gss_OID_set ret_mechs; - const gss_OID_set_desc FAR * valid_mechs; - int req_old, req_new; + int req_old, req_new, req_v2; OM_uint32 ret; krb5_error_code code; @@ -277,27 +302,24 @@ krb5_gss_acquire_cred(minor_status, desired_name, time_req, contains krb5 */ if (desired_mechs == GSS_C_NULL_OID_SET) { - valid_mechs = gss_mech_set_krb5_both; req_old = 1; req_new = 1; + req_v2 = 1; } else { req_old = 0; req_new = 0; + req_v2 = 0; for (i=0; i<desired_mechs->count; i++) { if (g_OID_equal(gss_mech_krb5_old, &(desired_mechs->elements[i]))) req_old++; if (g_OID_equal(gss_mech_krb5, &(desired_mechs->elements[i]))) req_new++; + if (g_OID_equal(gss_mech_krb5_v2, &(desired_mechs->elements[i]))) + req_v2++; } - if (req_old && req_new) { - valid_mechs = gss_mech_set_krb5_both; - } else if (req_old) { - valid_mechs = gss_mech_set_krb5_old; - } else if (req_new) { - valid_mechs = gss_mech_set_krb5; - } else { + if (!req_old && !req_new && !req_v2) { *minor_status = 0; return(GSS_S_BAD_MECH); } @@ -314,9 +336,9 @@ krb5_gss_acquire_cred(minor_status, desired_name, time_req, cred->usage = cred_usage; cred->princ = NULL; - cred->actual_mechs = valid_mechs; cred->prerfc_mech = req_old; cred->rfc_mech = req_new; + cred->rfcv2_mech = req_v2; cred->keytab = NULL; cred->ccache = NULL; @@ -407,17 +429,30 @@ krb5_gss_acquire_cred(minor_status, desired_name, time_req, /* create mechs */ if (actual_mechs) { - if (! g_copy_OID_set(cred->actual_mechs, &ret_mechs)) { - if (cred->ccache) - (void)krb5_cc_close(context, cred->ccache); - if (cred->keytab) - (void)krb5_kt_close(context, cred->keytab); - if (cred->princ) - krb5_free_principal(context, cred->princ); - xfree(cred); - *minor_status = ENOMEM; - return(GSS_S_FAILURE); - } + if (GSS_ERROR(ret = generic_gss_create_empty_oid_set(minor_status, + &ret_mechs)) || + (cred->prerfc_mech && + GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status, + gss_mech_krb5_old, + &ret_mechs))) || + (cred->rfc_mech && + GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status, + gss_mech_krb5, + &ret_mechs))) || + (cred->rfcv2_mech && + GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status, + gss_mech_krb5_v2, + &ret_mechs)))) { + if (cred->ccache) + (void)krb5_cc_close(context, cred->ccache); + if (cred->keytab) + (void)krb5_kt_close(context, cred->keytab); + if (cred->princ) + krb5_free_principal(context, cred->princ); + xfree(cred); + /* *minor_status set above */ + return(ret); + } } /* intern the credential handle */ @@ -445,39 +480,3 @@ krb5_gss_acquire_cred(minor_status, desired_name, time_req, return(GSS_S_COMPLETE); } - -/* V2 interface */ -OM_uint32 -krb5_gss_add_cred(minor_status, input_cred_handle, - desired_name, desired_mech, cred_usage, - initiator_time_req, acceptor_time_req, - output_cred_handle, actual_mechs, - initiator_time_rec, acceptor_time_rec) - OM_uint32 *minor_status; - gss_cred_id_t input_cred_handle; - gss_name_t desired_name; - gss_OID desired_mech; - gss_cred_usage_t cred_usage; - OM_uint32 initiator_time_req; - OM_uint32 acceptor_time_req; - gss_cred_id_t *output_cred_handle; - gss_OID_set *actual_mechs; - OM_uint32 *initiator_time_rec; - OM_uint32 *acceptor_time_rec; -{ - /* - * This does not apply to our single-mechanism implementation. Decide - * if the correct error is BAD_MECH or DUPLICATE_ELEMENT. - */ - - /* verify that the requested mechanism is the default, or - is krb5 */ - - if ((desired_mech != GSS_C_NULL_OID) && - (g_OID_equal(desired_mech, gss_mech_krb5))) - return(GSS_S_BAD_MECH); - - *minor_status = 0; - return(GSS_S_DUPLICATE_ELEMENT); -} - diff --git a/src/lib/gssapi/krb5/add_cred.c b/src/lib/gssapi/krb5/add_cred.c new file mode 100644 index 000000000..2a6fdb47b --- /dev/null +++ b/src/lib/gssapi/krb5/add_cred.c @@ -0,0 +1,309 @@ +/* + * Copyright (C) 1998 by the FundsXpress, INC. + * + * All rights reserved. + * + * Export of this software from the United States of America may require + * a specific license from the United States Government. It is the + * responsibility of any person or organization contemplating export to + * obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of FundsXpress. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. FundsXpress makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "gssapiP_krb5.h" +#ifdef HAVE_STRING_H +#include <string.h> +#else +#include <strings.h> +#endif + +/* + * $Id$ + */ + +/* V2 interface */ +OM_uint32 +krb5_gss_add_cred(minor_status, input_cred_handle, + desired_name, desired_mech, cred_usage, + initiator_time_req, acceptor_time_req, + output_cred_handle, actual_mechs, + initiator_time_rec, acceptor_time_rec) + OM_uint32 *minor_status; + gss_cred_id_t input_cred_handle; + gss_name_t desired_name; + gss_OID desired_mech; + gss_cred_usage_t cred_usage; + OM_uint32 initiator_time_req; + OM_uint32 acceptor_time_req; + gss_cred_id_t *output_cred_handle; + gss_OID_set *actual_mechs; + OM_uint32 *initiator_time_rec; + OM_uint32 *acceptor_time_rec; +{ + krb5_context context; + OM_uint32 major_status, lifetime; + krb5_gss_cred_id_t cred; + krb5_error_code code; + + /* this is pretty simple, since there's not really any difference + between the underlying mechanisms. The main hair is in copying + a mechanism if requested. */ + + /* check if the desired_mech is bogus */ + + if (!g_OID_equal(desired_mech, gss_mech_krb5_v2) && + !g_OID_equal(desired_mech, gss_mech_krb5) && + !g_OID_equal(desired_mech, gss_mech_krb5_old)) { + *minor_status = 0; + return(GSS_S_BAD_MECH); + } + + /* check if the desired_mech is bogus */ + + if ((cred_usage != GSS_C_INITIATE) && + (cred_usage != GSS_C_ACCEPT) && + (cred_usage != GSS_C_BOTH)) { + *minor_status = (OM_uint32) G_BAD_USAGE; + return(GSS_S_FAILURE); + } + + /* since the default credential includes all the mechanisms, + return an error for that case. */ + + /*SUPPRESS 29*/ + if (input_cred_handle == GSS_C_NO_CREDENTIAL) { + *minor_status = 0; + return(GSS_S_DUPLICATE_ELEMENT); + } + + /* verify the credential */ + if (GSS_ERROR(major_status = + krb5_gss_validate_cred(minor_status, input_cred_handle))) + return(major_status); + + cred = (krb5_gss_cred_id_t) input_cred_handle; + + /* check if the cred_usage is equal or "less" than the passed-in cred + if copying */ + + if (!((cred->usage == cred_usage) || + ((cred->usage == GSS_C_BOTH) && + (output_cred_handle != NULL)))) { + *minor_status = (OM_uint32) G_BAD_USAGE; + return(GSS_S_FAILURE); + } + + /* check that desired_mech isn't already in the credential */ + + if ((g_OID_equal(desired_mech, gss_mech_krb5_old) && cred->prerfc_mech) || + (g_OID_equal(desired_mech, gss_mech_krb5) && cred->rfc_mech) || + (g_OID_equal(desired_mech, gss_mech_krb5_v2) && cred->rfcv2_mech)) { + *minor_status = 0; + return(GSS_S_DUPLICATE_ELEMENT); + } + + if (GSS_ERROR(kg_get_context(minor_status, &context))) + return(GSS_S_FAILURE); + + /* verify the desired_name */ + + /*SUPPRESS 29*/ + if ((desired_name != (gss_name_t) NULL) && + (! kg_validate_name(desired_name))) { + *minor_status = (OM_uint32) G_VALIDATE_FAILED; + return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME); + } + + /* make sure the desired_name is the same as the existing one */ + + if (desired_name && + !krb5_principal_compare(context, (krb5_principal) desired_name, + cred->princ)) { + *minor_status = 0; + return(GSS_S_BAD_NAME); + } + + /* copy the cred if necessary */ + + if (output_cred_handle) { + /* make a copy */ + krb5_gss_cred_id_t new_cred; + char *kttype, ktboth[1024]; + char *cctype, *ccname, ccboth[1024]; + + if ((new_cred = + (krb5_gss_cred_id_t) xmalloc(sizeof(krb5_gss_cred_id_rec))) + == NULL) { + *minor_status = ENOMEM; + return(GSS_S_FAILURE); + } + memset(new_cred, 0, sizeof(krb5_gss_cred_id_rec)); + + new_cred->usage = cred_usage; + new_cred->prerfc_mech = cred->prerfc_mech; + new_cred->rfc_mech = cred->rfc_mech; + new_cred->rfcv2_mech = cred->rfcv2_mech; + new_cred->tgt_expire = cred->tgt_expire; + + if (code = krb5_copy_principal(context, cred->princ, + &new_cred->princ)) { + free(new_cred); + + *minor_status = code; + return(GSS_S_FAILURE); + } + + if (cred->keytab) { + kttype = krb5_kt_get_type(context, cred->keytab); + if ((strlen(kttype)+2) > sizeof(ktboth)) { + krb5_free_principal(context, new_cred->princ); + free(new_cred); + + *minor_status = ENOMEM; + return(GSS_S_FAILURE); + } + + strcpy(ktboth, kttype); + strcat(ktboth, ":"); + + if (code = krb5_kt_get_name(context, cred->keytab, + ktboth+strlen(ktboth), + sizeof(ktboth)-strlen(ktboth))) { + krb5_free_principal(context, new_cred->princ); + free(new_cred); + + *minor_status = code; + return(GSS_S_FAILURE); + } + + if (code = krb5_kt_resolve(context, ktboth, &new_cred->keytab)) { + krb5_free_principal(context, new_cred->princ); + free(new_cred); + + *minor_status = code; + return(GSS_S_FAILURE); + } + } else { + new_cred->keytab = NULL; + } + + if (cred->rcache) { + /* Open the replay cache for this principal. */ + if ((code = krb5_get_server_rcache(context, + krb5_princ_component(context, cred->princ, 0), + &new_cred->rcache))) { + if (new_cred->keytab) + krb5_kt_close(context, new_cred->keytab); + krb5_free_principal(context, new_cred->princ); + free(new_cred); + + *minor_status = code; + return(GSS_S_FAILURE); + } + } else { + new_cred->rcache = NULL; + } + + if (cred->ccache) { + cctype = krb5_cc_get_type(context, cred->ccache); + ccname = krb5_cc_get_name(context, cred->ccache); + + if ((strlen(cctype)+strlen(ccname)+2) > sizeof(ccboth)) { + if (new_cred->rcache) + krb5_rc_close(context, new_cred->rcache); + if (new_cred->keytab) + krb5_kt_close(context, new_cred->keytab); + krb5_free_principal(context, new_cred->princ); + free(new_cred); + + *minor_status = ENOMEM; + return(GSS_S_FAILURE); + } + + strcpy(ccboth, cctype); + strcat(ccboth, ":"); + strcat(ccboth, ccname); + + if (code = krb5_cc_resolve(context, ccboth, &new_cred->ccache)) { + if (new_cred->rcache) + krb5_rc_close(context, new_cred->rcache); + if (new_cred->keytab) + krb5_kt_close(context, new_cred->keytab); + krb5_free_principal(context, new_cred->princ); + free(new_cred); + + *minor_status = code; + return(GSS_S_FAILURE); + } + } else { + new_cred->ccache = NULL; + } + + /* intern the credential handle */ + + if (! kg_save_cred_id((gss_cred_id_t) new_cred)) { + if (new_cred->ccache) + krb5_cc_close(context, new_cred->ccache); + if (new_cred->rcache) + krb5_rc_close(context, new_cred->rcache); + if (new_cred->keytab) + krb5_kt_close(context, new_cred->keytab); + krb5_free_principal(context, new_cred->princ); + free(new_cred); + + *minor_status = (OM_uint32) G_VALIDATE_FAILED; + return(GSS_S_FAILURE); + } + + /* modify new_cred */ + + cred = new_cred; + } + + /* set the flag for the new mechanism */ + + if (g_OID_equal(desired_mech, gss_mech_krb5_old)) + cred->prerfc_mech = 1; + else if (g_OID_equal(desired_mech, gss_mech_krb5)) + cred->rfc_mech = 1; + else if (g_OID_equal(desired_mech, gss_mech_krb5_v2)) + cred->rfcv2_mech = 1; + + /* set the outputs */ + + if (GSS_ERROR(major_status = krb5_gss_inquire_cred(minor_status, cred, + NULL, &lifetime, + NULL, actual_mechs))) { + OM_uint32 dummy; + + if (output_cred_handle) + (void) krb5_gss_release_cred(&dummy, (gss_cred_id_t *) &cred); + + return(major_status); + } + + if (initiator_time_rec) + *initiator_time_rec = lifetime; + if (acceptor_time_rec) + *acceptor_time_rec = lifetime; + + if (output_cred_handle) + *output_cred_handle = cred; + + *minor_status = 0; + return(GSS_S_COMPLETE); +} diff --git a/src/lib/gssapi/krb5/canon_name.c b/src/lib/gssapi/krb5/canon_name.c index 652745c7b..688366e1f 100644 --- a/src/lib/gssapi/krb5/canon_name.c +++ b/src/lib/gssapi/krb5/canon_name.c @@ -31,13 +31,12 @@ OM_uint32 krb5_gss_canonicalize_name(OM_uint32 *minor_status, const gss_OID mech_type, gss_name_t *output_name) { - if ((mech_type == GSS_C_NULL_OID) || - !g_OID_equal(mech_type, gss_mech_krb5)) { - if (minor_status) - *minor_status = 0; - return(GSS_S_BAD_MECH); - } - - return gss_duplicate_name(minor_status, input_name, - output_name); + if (!g_OID_equal(gss_mech_krb5_v2, mech_type) && + !g_OID_equal(gss_mech_krb5, mech_type) && + !g_OID_equal(gss_mech_krb5_old, mech_type)) { + *minor_status = 0; + return(GSS_S_BAD_MECH); + } + + return(gss_duplicate_name(minor_status, input_name, output_name)); } diff --git a/src/lib/gssapi/krb5/delete_sec_context.c b/src/lib/gssapi/krb5/delete_sec_context.c index 16964995a..28c235890 100644 --- a/src/lib/gssapi/krb5/delete_sec_context.c +++ b/src/lib/gssapi/krb5/delete_sec_context.c @@ -80,15 +80,11 @@ krb5_gss_delete_sec_context(minor_status, context_handle, output_token) if (ctx->seqstate) g_order_free(&(ctx->seqstate)); - if (ctx->enc.processed) - krb5_finish_key(context, &ctx->enc.eblock); - if (ctx->enc.key) - krb5_free_keyblock(context, ctx->enc.key); + if (ctx->enc) + krb5_free_keyblock(context, ctx->enc); - if (ctx->seq.processed) - krb5_finish_key(context, &ctx->seq.eblock); - if (ctx->seq.key) - krb5_free_keyblock(context, ctx->seq.key); + if (ctx->seq) + krb5_free_keyblock(context, ctx->seq); if (ctx->here) krb5_free_principal(context, ctx->here); @@ -105,6 +101,9 @@ krb5_gss_delete_sec_context(minor_status, context_handle, output_token) if (ctx->mech_used) gss_release_oid(minor_status, &ctx->mech_used); + if (ctx->ctypes) + xfree(ctx->ctypes); + /* Zero out context */ memset(ctx, 0, sizeof(*ctx)); xfree(ctx); diff --git a/src/lib/gssapi/krb5/disp_status.c b/src/lib/gssapi/krb5/disp_status.c index 4dc13843c..3a6ba7b1a 100644 --- a/src/lib/gssapi/krb5/disp_status.c +++ b/src/lib/gssapi/krb5/disp_status.c @@ -49,10 +49,12 @@ krb5_gss_display_status(minor_status, status_value, status_type, return(GSS_S_FAILURE); if ((mech_type != GSS_C_NULL_OID) && - (! g_OID_equal(gss_mech_krb5, mech_type))) { - *minor_status = 0; - return(GSS_S_BAD_MECH); - } + !g_OID_equal(gss_mech_krb5_v2, mech_type) && + !g_OID_equal(gss_mech_krb5, mech_type) && + !g_OID_equal(gss_mech_krb5_old, mech_type)) { + *minor_status = 0; + return(GSS_S_BAD_MECH); + } if (status_type == GSS_C_GSS_CODE) { return(g_display_major_status(minor_status, status_value, diff --git a/src/lib/gssapi/krb5/gssapiP_krb5.h b/src/lib/gssapi/krb5/gssapiP_krb5.h index 11b7c50f4..bcbde3894 100644 --- a/src/lib/gssapi/krb5/gssapiP_krb5.h +++ b/src/lib/gssapi/krb5/gssapiP_krb5.h @@ -68,8 +68,17 @@ ((x) & (GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | \ GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG))) +#define KG2_TOK_INITIAL 0x0101 +#define KG2_TOK_RESPONSE 0x0202 +#define KG2_TOK_MIC 0x0303 +#define KG2_TOK_WRAP_INTEG 0x0404 +#define KG2_TOK_WRAP_PRIV 0x0505 + #define KRB5_GSS_FOR_CREDS_OPTION 1 +#define KG2_RESP_FLAG_ERROR 0x0001 +#define KG2_RESP_FLAG_DELEG_OK 0x0002 + /** internal types **/ typedef krb5_principal krb5_gss_name_t; @@ -78,25 +87,19 @@ typedef struct _krb5_gss_cred_id_rec { /* name/type of credential */ gss_cred_usage_t usage; krb5_principal princ; /* this is not interned as a gss_name_t */ - const gss_OID_set_desc *actual_mechs; - int prerfc_mech; /* these are a cache of the set above */ + int prerfc_mech; int rfc_mech; + int rfcv2_mech; /* keytab (accept) data */ krb5_keytab keytab; + krb5_rcache rcache; /* ccache (init) data */ krb5_ccache ccache; krb5_timestamp tgt_expire; - krb5_rcache rcache; } krb5_gss_cred_id_rec, *krb5_gss_cred_id_t; -typedef struct _krb5_gss_enc_desc { - int processed; - krb5_keyblock *key; - krb5_encrypt_block eblock; -} krb5_gss_enc_desc; - typedef struct _krb5_gss_ctx_id_rec { int initiate; /* nonzero if initiating, zero if accepting */ OM_uint32 gss_flags; @@ -108,21 +111,35 @@ typedef struct _krb5_gss_ctx_id_rec { int signalg; int cksum_size; int sealalg; - krb5_gss_enc_desc enc; - krb5_gss_enc_desc seq; + krb5_keyblock *enc; + krb5_keyblock *seq; krb5_timestamp endtime; krb5_flags krb_flags; - krb5_int32 seq_send; - krb5_int32 seq_recv; + /* XXX these used to be signed. the old spec is inspecific, and + the new spec specifies unsigned. I don't believe that the change + affects the wire encoding. */ + krb5_ui_4 seq_send; + krb5_ui_4 seq_recv; void *seqstate; int established; int big_endian; krb5_auth_context auth_context; gss_OID_desc *mech_used; + int gsskrb5_version; + int nctypes; + krb5_cksumtype *ctypes; } krb5_gss_ctx_id_rec, *krb5_gss_ctx_id_t; extern void *kg_vdb; +struct kg2_option { + int option_id; /* set by caller */ + int length; /* filled in by parser */ + unsigned char *data; /* filled in by parser. points inside + passed-in token, so nothing needs to + be freed */ +}; + /* helper macros */ #define kg_save_name(name) g_save_name(&kg_vdb,name) @@ -151,12 +168,12 @@ krb5_error_code kg_checksum_channel_bindings int bigend)); krb5_error_code kg_make_seq_num PROTOTYPE((krb5_context context, - krb5_gss_enc_desc *ed, + krb5_keyblock *key, int direction, krb5_int32 seqnum, unsigned char *cksum, unsigned char *buf)); krb5_error_code kg_get_seq_num PROTOTYPE((krb5_context context, - krb5_gss_enc_desc *ed, + krb5_keyblock *key, unsigned char *cksum, unsigned char *buf, int *direction, krb5_int32 *seqnum)); @@ -164,19 +181,20 @@ krb5_error_code kg_make_seed PROTOTYPE((krb5_context context, krb5_keyblock *key, unsigned char *seed)); -int kg_confounder_size PROTOTYPE((krb5_gss_enc_desc *ed)); +int kg_confounder_size PROTOTYPE((krb5_context context, krb5_keyblock *key)); -krb5_error_code kg_make_confounder PROTOTYPE((krb5_gss_enc_desc *ed, - unsigned char *buf)); +krb5_error_code kg_make_confounder PROTOTYPE((krb5_context context, + krb5_keyblock *key, unsigned char *buf)); -int kg_encrypt_size PROTOTYPE((krb5_gss_enc_desc *ed, int n)); +int kg_encrypt_size PROTOTYPE((krb5_context context, + krb5_keyblock *key, int n)); krb5_error_code kg_encrypt PROTOTYPE((krb5_context context, - krb5_gss_enc_desc *ed, + krb5_keyblock *key, krb5_pointer iv, krb5_pointer in, krb5_pointer out, int length)); krb5_error_code kg_decrypt PROTOTYPE((krb5_context context, - krb5_gss_enc_desc *ed, + krb5_keyblock *key, krb5_pointer iv, krb5_pointer in, krb5_pointer out, int length)); OM_uint32 kg_seal PROTOTYPE((krb5_context context, @@ -223,6 +241,23 @@ krb5_error_code kg_ctx_internalize PROTOTYPE((krb5_context kcontext, OM_uint32 kg_get_context PROTOTYPE((OM_uint32 *minor_status, krb5_context *context)); +OM_uint32 +kg2_parse_token PROTOTYPE((OM_uint32 *minor_status, + unsigned char *ptr, + int length, + krb5_ui_4 *flags, + int *nctypes, /* OUT */ + krb5_cksumtype **ctypes, /* OUT */ + int noptions, + struct kg2_option *options, /* INOUT */ + krb5_data *kmsg, + krb5_data *mic)); + +void kg2_intersect_ctypes PROTOTYPE((int *nc1, + krb5_cksumtype *c1, + int nc2, + const krb5_cksumtype *c2)); + /** declarations of internal name mechanism functions **/ OM_uint32 krb5_gss_acquire_cred diff --git a/src/lib/gssapi/krb5/gssapi_err_krb5.et b/src/lib/gssapi/krb5/gssapi_err_krb5.et index 54a126518..3c9be6351 100644 --- a/src/lib/gssapi/krb5/gssapi_err_krb5.et +++ b/src/lib/gssapi/krb5/gssapi_err_krb5.et @@ -35,4 +35,5 @@ error_code KG_CRED, "Bad magic number for krb5_gss_cred_id_t" error_code KG_ENC_DESC, "Bad magic number for krb5_gss_enc_desc" error_code KG_BAD_SEQ, "Sequence number in token is corrupt" error_code KG_EMPTY_CCACHE, "Credential cache is empty" +error_code KG_NO_CTYPES, "Acceptor and Initiator share no checksum types" end diff --git a/src/lib/gssapi/krb5/gssapi_krb5.c b/src/lib/gssapi/krb5/gssapi_krb5.c index c0942c39a..aaa47ea06 100644 --- a/src/lib/gssapi/krb5/gssapi_krb5.c +++ b/src/lib/gssapi/krb5/gssapi_krb5.c @@ -21,6 +21,32 @@ */ /* + * Copyright (C) 1998 by the FundsXpress, INC. + * + * All rights reserved. + * + * Export of this software from the United States of America may require + * a specific license from the United States Government. It is the + * responsibility of any person or organization contemplating export to + * obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of FundsXpress. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. FundsXpress makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* * $Id$ */ @@ -43,6 +69,9 @@ * The OID of the proposed standard krb5 mechanism is: * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2) * krb5(2) = 1.2.840.113554.1.2.2 + * The OID of the proposed standard krb5 v2 mechanism is: + * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2) + * krb5v2(3) = 1.2.840.113554.1.2.3 * */ @@ -58,8 +87,13 @@ const gss_OID_desc krb5_gss_oid_array[] = { {5, "\053\005\001\005\002"}, /* this is the official, rfc-specified OID */ {9, "\052\206\110\206\367\022\001\002\002"}, + /* these two are name type OID's */ {10, "\052\206\110\206\367\022\001\002\002\001"}, {10, "\052\206\110\206\367\022\001\002\002\002"}, + /* this is the v2 assigned OID */ + {9, "\052\206\110\206\367\022\001\002\003"}, + /* this is the official, rfc-specified OID again */ + {9, "\052\206\110\206\367\022\001\002\002"}, { 0, 0 } }; @@ -67,16 +101,21 @@ const gss_OID_desc * const gss_mech_krb5_old = krb5_gss_oid_array+0; const gss_OID_desc * const gss_mech_krb5 = krb5_gss_oid_array+1; const gss_OID_desc * const gss_nt_krb5_name = krb5_gss_oid_array+2; const gss_OID_desc * const gss_nt_krb5_principal = krb5_gss_oid_array+3; +const gss_OID_desc * const gss_mech_krb5_v2 = krb5_gss_oid_array+4; static const gss_OID_set_desc oidsets[] = { {1, (gss_OID) krb5_gss_oid_array+0}, {1, (gss_OID) krb5_gss_oid_array+1}, {2, (gss_OID) krb5_gss_oid_array+0}, + {1, (gss_OID) krb5_gss_oid_array+4}, + {2, (gss_OID) krb5_gss_oid_array+4}, }; const gss_OID_set_desc * const gss_mech_set_krb5_old = oidsets+0; const gss_OID_set_desc * const gss_mech_set_krb5 = oidsets+1; const gss_OID_set_desc * const gss_mech_set_krb5_both = oidsets+2; +const gss_OID_set_desc * const gss_mech_set_krb5_v2 = oidsets+3; +const gss_OID_set_desc * const gss_mech_set_krb5_v1v2 = oidsets+4; void *kg_vdb = NULL; diff --git a/src/lib/gssapi/krb5/gssapi_krb5.h b/src/lib/gssapi/krb5/gssapi_krb5.h index 63ac530f3..e4eccbb42 100644 --- a/src/lib/gssapi/krb5/gssapi_krb5.h +++ b/src/lib/gssapi/krb5/gssapi_krb5.h @@ -32,9 +32,12 @@ extern const gss_OID_desc * const gss_mech_krb5; extern const gss_OID_desc * const gss_mech_krb5_old; +extern const gss_OID_desc * const gss_mech_krb5_v2; extern const gss_OID_set_desc * const gss_mech_set_krb5; extern const gss_OID_set_desc * const gss_mech_set_krb5_old; extern const gss_OID_set_desc * const gss_mech_set_krb5_both; +extern const gss_OID_set_desc * const gss_mech_set_krb5_v2; +extern const gss_OID_set_desc * const gss_mech_set_krb5_v1v2; extern const gss_OID_desc * const gss_nt_krb5_name; extern const gss_OID_desc * const gss_nt_krb5_principal; diff --git a/src/lib/gssapi/krb5/init_sec_context.c b/src/lib/gssapi/krb5/init_sec_context.c index 50855b58c..4ff2085b4 100644 --- a/src/lib/gssapi/krb5/init_sec_context.c +++ b/src/lib/gssapi/krb5/init_sec_context.c @@ -20,6 +20,32 @@ * PERFORMANCE OF THIS SOFTWARE. */ +/* + * Copyright (C) 1998 by the FundsXpress, INC. + * + * All rights reserved. + * + * Export of this software from the United States of America may require + * a specific license from the United States Government. It is the + * responsibility of any person or organization contemplating export to + * obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of FundsXpress. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. FundsXpress makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + #include "gssapiP_krb5.h" #include <memory.h> #include <stdlib.h> @@ -33,8 +59,257 @@ int krb5_gss_dbg_client_expcreds = 0; static krb5_error_code -make_ap_req(context, auth_context, cred, server, now, endtime, chan_bindings, - req_flags, krb_flags, mech_type, token) +make_ap_req_v2(context, auth_context, cred, server, now, endtime, + chan_bindings, req_flags, krb_flags, mech_type, + ret_nctypes, ret_ctypes, token) + krb5_context context; + krb5_auth_context * auth_context; + krb5_gss_cred_id_t cred; + krb5_principal server; + krb5_timestamp now; + krb5_timestamp *endtime; + gss_channel_bindings_t chan_bindings; + OM_uint32 *req_flags; + krb5_flags *krb_flags; + gss_OID mech_type; + int *ret_nctypes; + krb5_cksumtype **ret_ctypes; + gss_buffer_t token; +{ + krb5_flags mk_req_flags = 0; + krb5_int32 con_flags; + krb5_error_code code; + krb5_creds in_creds, *out_creds = 0; + krb5_data credmsg, cksumdata, ap_req; + int i, tlen, cblen, nctypes; + krb5_cksumtype *ctypes; + unsigned char *t, *ptr; + + credmsg.data = 0; + cksumdata.data = 0; + ap_req.data = 0; + ctypes = 0; + + /* this probably isn't necessary */ + if (*auth_context) + krb5_auth_con_free(context, *auth_context); + + *auth_context = 0; + + /* create the option data if necessary */ + + if (*req_flags & GSS_C_DELEG_FLAG) { + /* first get KRB_CRED message, so we know its length */ + + /* clear the time check flag that was set in krb5_auth_con_init() */ + krb5_auth_con_getflags(context, *auth_context, &con_flags); + krb5_auth_con_setflags(context, *auth_context, + con_flags & ~KRB5_AUTH_CONTEXT_DO_TIME); + + code = krb5_fwd_tgt_creds(context, *auth_context, 0, + cred->princ, server, cred->ccache, 1, + &credmsg); + + /* turn KRB5_AUTH_CONTEXT_DO_TIME back on */ + krb5_auth_con_setflags(context, *auth_context, con_flags); + + if (code) { + /* don't fail here; just don't accept/do the delegation + request */ + *req_flags &= ~GSS_C_DELEG_FLAG; + } else { + if (credmsg.length > KRB5_INT16_MAX) { + krb5_free_data_contents(context, &credmsg); + return(KRB5KRB_ERR_FIELD_TOOLONG); + } + } + } else { + credmsg.length = 0; + } + + /* + * Get the credential, for the session key etype + */ + + memset((char *) &in_creds, 0, sizeof(krb5_creds)); + + if ((code = krb5_copy_principal(context, cred->princ, &in_creds.client))) + goto cleanup; + if ((code = krb5_copy_principal(context, server, &in_creds.server))) + goto cleanup; + in_creds.times.endtime = *endtime; + + if ((code = krb5_get_credentials(context, 0, cred->ccache, + &in_creds, &out_creds))) + goto cleanup; + + /* + * Enforce a stricter limit (without timeskew forgiveness at the + * boundaries) because accept_sec_context code is also similarly + * non-forgiving. + */ + if (!krb5_gss_dbg_client_expcreds && out_creds->times.endtime < now) { + code = KRB5KRB_AP_ERR_TKT_EXPIRED; + goto cleanup; + } + + /* construct the list of compatible cksum types */ + + if (code = krb5_c_keyed_checksum_types(context, + out_creds->keyblock.enctype, + &nctypes, &ctypes)) + goto cleanup; + + if (nctypes == 0) { + code = KRB5_CRYPTO_INTERNAL; + goto cleanup; + } + + /* construct the checksum fields */ + + cblen = 4*5; + if (chan_bindings) + cblen += (chan_bindings->initiator_address.length+ + chan_bindings->acceptor_address.length+ + chan_bindings->application_data.length); + + cksumdata.length = cblen + 8 + 4*nctypes + 4; + if (credmsg.length) + cksumdata.length += 4 + credmsg.length; + + if ((cksumdata.data = (char *) malloc(cksumdata.length)) == NULL) + goto cleanup; + + /* helper macros. This code currently depends on a long being 32 + bits, and htonl dtrt. */ + + ptr = cksumdata.data; + + if (chan_bindings) { + TWRITE_INT(ptr, chan_bindings->initiator_addrtype, 1); + TWRITE_BUF(ptr, chan_bindings->initiator_address, 1); + TWRITE_INT(ptr, chan_bindings->acceptor_addrtype, 1); + TWRITE_BUF(ptr, chan_bindings->acceptor_address, 1); + TWRITE_BUF(ptr, chan_bindings->application_data, 1); + } else { + memset(ptr, 0, cblen); + ptr += cblen; + } + + /* construct the token fields */ + + ptr[0] = (KG2_TOK_INITIAL >> 8) & 0xff; + ptr[1] = KG2_TOK_INITIAL & 0xff; + + ptr[2] = (*req_flags >> 24) & 0xff; + ptr[3] = (*req_flags >> 16) & 0xff; + ptr[4] = (*req_flags >> 8) & 0xff; + ptr[5] = *req_flags & 0xff; + + ptr[6] = (nctypes >> 8) & 0xff; + ptr[7] = nctypes & 0xff; + + ptr += 8; + + for (i=0; i<nctypes; i++) { + ptr[0] = (ctypes[i] >> 24) & 0xff; + ptr[1] = (ctypes[i] >> 16) & 0xff; + ptr[2] = (ctypes[i] >> 8) & 0xff; + ptr[3] = ctypes[i] & 0xff; + + ptr += 4; + } + + if (credmsg.length) { + ptr[0] = (KRB5_GSS_FOR_CREDS_OPTION >> 8) & 0xff; + ptr[1] = KRB5_GSS_FOR_CREDS_OPTION & 0xff; + + ptr[2] = (credmsg.length >> 8) & 0xff; + ptr[3] = credmsg.length & 0xff; + + ptr += 4; + + memcpy(ptr, credmsg.data, credmsg.length); + + ptr += credmsg.length; + } + + memset(ptr, 0, 4); + + /* call mk_req. subkey and ap_req need to be used or destroyed */ + + mk_req_flags = AP_OPTS_USE_SUBKEY; + + if (*req_flags & GSS_C_MUTUAL_FLAG) + mk_req_flags |= AP_OPTS_MUTUAL_REQUIRED; + + if ((code = krb5_mk_req_extended(context, auth_context, mk_req_flags, + &cksumdata, out_creds, &ap_req))) + goto cleanup; + + /* store the interesting stuff from creds and authent */ + *endtime = out_creds->times.endtime; + *krb_flags = out_creds->ticket_flags; + + /* build up the token */ + + /* allocate space for the token */ + tlen = g_token_size((gss_OID) mech_type, + (cksumdata.length-(2+cblen))+2+ap_req.length); + + if ((t = (unsigned char *) xmalloc(tlen)) == NULL) { + code = ENOMEM; + goto cleanup; + } + + ptr = t; + + g_make_token_header((gss_OID) mech_type, + (cksumdata.length-(2+cblen))+2+ap_req.length, + &ptr, KG2_TOK_INITIAL); + + /* skip over the channel bindings and the token id */ + memcpy(ptr, cksumdata.data+cblen+2, cksumdata.length-(cblen+2)); + ptr += cksumdata.length-(cblen+2); + ptr[0] = (ap_req.length >> 8) & 0xff; + ptr[1] = ap_req.length & 0xff; + ptr += 2; + memcpy(ptr, ap_req.data, ap_req.length); + + /* pass allocated data back */ + + *ret_nctypes = nctypes; + *ret_ctypes = ctypes; + + token->length = tlen; + token->value = (void *) t; + + code = 0; + +cleanup: + if (code) { + if (*auth_context) + krb5_auth_con_free(context, *auth_context); + if (ctypes) + krb5_free_cksumtypes(context, ctypes); + } + + if (out_creds) + krb5_free_creds(context, out_creds); + krb5_free_cred_contents(context, &in_creds); + if (credmsg.data) + free(credmsg.data); + if (ap_req.data) + free(ap_req.data); + if (cksumdata.data) + free(cksumdata.data); + + return(code); +} + +static krb5_error_code +make_ap_req_v1(context, auth_context, cred, server, now, endtime, + chan_bindings, req_flags, krb_flags, mech_type, token) krb5_context context; krb5_auth_context * auth_context; krb5_gss_cred_id_t cred; @@ -142,15 +417,16 @@ make_ap_req(context, auth_context, cred, server, now, endtime, chan_bindings, /* fill in the necessary fields in creds */ memset((char *) &in_creds, 0, sizeof(krb5_creds)); + if ((code = krb5_copy_principal(context, cred->princ, &in_creds.client))) goto cleanup; if ((code = krb5_copy_principal(context, server, &in_creds.server))) goto cleanup; - in_creds.keyblock.enctype = ENCTYPE_DES_CBC_CRC; in_creds.times.endtime = *endtime; + in_creds.keyblock.enctype = ENCTYPE_DES_CBC_CRC; /* - * Get the credential..., I don't know in 0 is a good value for the + * Get the credential..., I don't know if 0 is a good value for the * kdcoptions */ if ((code = krb5_get_credentials(context, 0, cred->ccache, @@ -222,10 +498,6 @@ cleanup: return (code); } -#define IS_KRB_ERROR(dat)\ - ((dat) && (dat)->length && ((dat)->data[0] == 0x7e ||\ - (dat)->data[0] == 0x5e)) - OM_uint32 krb5_gss_init_sec_context(minor_status, claimant_cred_handle, context_handle, target_name, mech_type, @@ -251,10 +523,11 @@ krb5_gss_init_sec_context(minor_status, claimant_cred_handle, krb5_error_code code; krb5_gss_ctx_id_rec *ctx; krb5_timestamp now; - krb5_enctype enctype; gss_buffer_desc token; - int i; - int err; + int gsskrb5_vers; + int i, err; + krb5_ui_4 resp_flags, field_length, opt_id; + OM_uint32 major_status, dummy; if (GSS_ERROR(kg_get_context(minor_status, &context))) return(GSS_S_FAILURE); @@ -289,15 +562,33 @@ krb5_gss_init_sec_context(minor_status, claimant_cred_handle, err = 0; if (mech_type == GSS_C_NULL_OID) { - mech_type = cred->rfc_mech?gss_mech_krb5:gss_mech_krb5_old; + if (cred->rfcv2_mech) { + mech_type = gss_mech_krb5_v2; + gsskrb5_vers = 2000; + } else if (cred->rfc_mech) { + mech_type = gss_mech_krb5; + gsskrb5_vers = 1000; + } else if (cred->prerfc_mech) { + mech_type = gss_mech_krb5_old; + gsskrb5_vers = 1000; + } else { + err = 1; + } + } else if (g_OID_equal(mech_type, gss_mech_krb5_v2)) { + if (!cred->rfcv2_mech) + err = 1; + gsskrb5_vers = 2000; } else if (g_OID_equal(mech_type, gss_mech_krb5)) { if (!cred->rfc_mech) err = 1; + gsskrb5_vers = 1000; } else if (g_OID_equal(mech_type, gss_mech_krb5_old)) { if (!cred->prerfc_mech) err = 1; - } else + gsskrb5_vers = 1000; + } else { err = 1; + } if (err) { *minor_status = 0; @@ -351,6 +642,9 @@ krb5_gss_init_sec_context(minor_status, claimant_cred_handle, ctx->seed_init = 0; ctx->big_endian = 0; /* all initiators do little-endian, as per spec */ ctx->seqstate = 0; + ctx->gsskrb5_version = gsskrb5_vers; + ctx->nctypes = 0; + ctx->ctypes = 0; if ((code = krb5_timeofday(context, &now))) { free(ctx); @@ -377,63 +671,94 @@ krb5_gss_init_sec_context(minor_status, claimant_cred_handle, return(GSS_S_FAILURE); } - if ((code = make_ap_req(context, &(ctx->auth_context), cred, - ctx->there, now, &ctx->endtime, - input_chan_bindings, - &ctx->gss_flags, &ctx->krb_flags, mech_type, - &token))) { - krb5_free_principal(context, ctx->here); - krb5_free_principal(context, ctx->there); - xfree(ctx); - *minor_status = code; - - if ((code == KRB5_FCC_NOFILE) || (code == KRB5_CC_NOTFOUND) || - (code == KG_EMPTY_CCACHE)) - return GSS_S_NO_CRED; - if (code == KRB5KRB_AP_ERR_TKT_EXPIRED) - return GSS_S_CREDENTIALS_EXPIRED; - return(GSS_S_FAILURE); - } - - krb5_auth_con_getlocalseqnumber(context, ctx->auth_context, &ctx->seq_send); - krb5_auth_con_getlocalsubkey(context, ctx->auth_context, &ctx->subkey); - - /* fill in the encryption descriptors */ - - switch(ctx->subkey->enctype) { - case ENCTYPE_DES_CBC_MD5: - case ENCTYPE_DES_CBC_CRC: - enctype = ENCTYPE_DES_CBC_RAW; - ctx->signalg = 0; - ctx->cksum_size = 8; - ctx->sealalg = 0; - break; + if (ctx->gsskrb5_version == 2000) { + /* gsskrb5 v2 */ + + ctx->gss_flags & ~GSS_C_DELEG_FLAG; + + if ((code = make_ap_req_v2(context, &(ctx->auth_context), cred, + ctx->there, now, &ctx->endtime, + input_chan_bindings, + &ctx->gss_flags, &ctx->krb_flags, + mech_type, &ctx->nctypes, &ctx->ctypes, + &token))) { + krb5_free_principal(context, ctx->here); + krb5_free_principal(context, ctx->there); + xfree(ctx); + *minor_status = code; + + if ((code == KRB5_FCC_NOFILE) || (code == KRB5_CC_NOTFOUND) || + (code == KG_EMPTY_CCACHE)) + return GSS_S_NO_CRED; + if (code == KRB5KRB_AP_ERR_TKT_EXPIRED) + return GSS_S_CREDENTIALS_EXPIRED; + return(GSS_S_FAILURE); + } + + krb5_auth_con_getlocalseqnumber(context, ctx->auth_context, + &ctx->seq_send); + krb5_auth_con_getlocalsubkey(context, ctx->auth_context, + &ctx->subkey); + } else { + /* gsskrb5 v1 */ + + if ((code = make_ap_req_v1(context, &(ctx->auth_context), cred, + ctx->there, now, &ctx->endtime, + input_chan_bindings, + &ctx->gss_flags, &ctx->krb_flags, + mech_type, + &token))) { + krb5_free_principal(context, ctx->here); + krb5_free_principal(context, ctx->there); + xfree(ctx); + *minor_status = code; + + if ((code == KRB5_FCC_NOFILE) || (code == KRB5_CC_NOTFOUND) || + (code == KG_EMPTY_CCACHE)) + return GSS_S_NO_CRED; + if (code == KRB5KRB_AP_ERR_TKT_EXPIRED) + return GSS_S_CREDENTIALS_EXPIRED; + return(GSS_S_FAILURE); + } + + krb5_auth_con_getlocalseqnumber(context, ctx->auth_context, + &ctx->seq_send); + krb5_auth_con_getlocalsubkey(context, ctx->auth_context, + &ctx->subkey); + + /* fill in the encryption descriptors */ + + switch(ctx->subkey->enctype) { + case ENCTYPE_DES_CBC_MD5: + case ENCTYPE_DES_CBC_CRC: + ctx->subkey->enctype = ENCTYPE_DES_CBC_RAW; + ctx->signalg = 0; + ctx->cksum_size = 8; + ctx->sealalg = 0; + break; #if 0 - case ENCTYPE_DES3_CBC_MD5: - enctype = ENCTYPE_DES3_CBC_RAW; - ctx->signalg = 3; - ctx->cksum_size = 16; - ctx->sealalg = 1; - break; + case ENCTYPE_DES3_CBC_MD5: + enctype = ENCTYPE_DES3_CBC_RAW; + ctx->signalg = 3; + ctx->cksum_size = 16; + ctx->sealalg = 1; + break; #endif - default: - return GSS_S_FAILURE; - } + default: + return GSS_S_FAILURE; + } - /* the encryption key is the session key XOR 0xf0f0f0f0f0f0f0f0 */ + /* the encryption key is the session key XOR 0xf0f0f0f0f0f0f0f0 */ - krb5_use_enctype(context, &ctx->enc.eblock, enctype); - ctx->enc.processed = 0; - if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc.key))) - return(code); - for (i=0; i<ctx->enc.key->length; i++) - /*SUPPRESS 113*/ - ctx->enc.key->contents[i] ^= 0xf0; + if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc))) + return(code); + for (i=0; i<ctx->enc->length; i++) + /*SUPPRESS 113*/ + ctx->enc->contents[i] ^= 0xf0; - krb5_use_enctype(context, &ctx->seq.eblock, enctype); - ctx->seq.processed = 0; - if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->seq.key))) - return(code); + if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->seq))) + return(code); + } /* at this point, the context is constructed and valid, hence, releaseable */ @@ -493,7 +818,7 @@ krb5_gss_init_sec_context(minor_status, claimant_cred_handle, } else { unsigned char *ptr; char *sptr; - krb5_data ap_rep; + krb5_data ap_rep, mic; krb5_ap_rep_enc_part *ap_rep_data; krb5_error *krb_error; @@ -512,11 +837,8 @@ krb5_gss_init_sec_context(minor_status, claimant_cred_handle, if ((ctx->established) || (((gss_cred_id_t) cred) != claimant_cred_handle) || ((ctx->gss_flags & GSS_C_MUTUAL_FLAG) == 0)) { - (void)krb5_gss_delete_sec_context(minor_status, - context_handle, NULL); - /* XXX this minor status is wrong if an arg was changed */ - *minor_status = KG_CONTEXT_ESTABLISHED; - return(GSS_S_FAILURE); + code = KG_CONTEXT_ESTABLISHED; + goto fail; } if (! krb5_principal_compare(context, ctx->there, @@ -538,47 +860,106 @@ krb5_gss_init_sec_context(minor_status, claimant_cred_handle, ptr = (unsigned char *) input_token->value; - if ((err = g_verify_token_header((gss_OID) mech_type, &(ap_rep.length), - &ptr, KG_TOK_CTX_AP_REP, - input_token->length))) { + if (ctx->gsskrb5_version == 2000) { + int token_length; + int nctypes; + krb5_cksumtype *ctypes; + + /* gsskrb5 v2 */ + + if ((err = g_verify_token_header((gss_OID) mech_type, + &token_length, + &ptr, KG2_TOK_RESPONSE, + input_token->length))) { + (void)krb5_gss_delete_sec_context(minor_status, + context_handle, NULL); + *minor_status = err; + return(GSS_S_DEFECTIVE_TOKEN); + } + + if (GSS_ERROR(major_status = + kg2_parse_token(minor_status, ptr, token_length, + &resp_flags, &nctypes, &ctypes, + 0, NULL, &ap_rep, &mic))) { + free(ctypes); + (void)krb5_gss_delete_sec_context(&dummy, context_handle, NULL); + return(major_status); + } + + kg2_intersect_ctypes(&ctx->nctypes, ctx->ctypes, nctypes, ctypes); + + free(ctypes); + + if (ctx->nctypes == 0) { + code = KG_NO_CTYPES; + goto fail; + } + + if (resp_flags & KG2_RESP_FLAG_ERROR) { + if (code = krb5_rd_error(context, &ap_rep, &krb_error)) + goto fail; + + if (krb_error->error) + code = krb_error->error + ERROR_TABLE_BASE_krb5; + else + code = 0; + + krb5_free_error(context, krb_error); + + goto fail; + } + + if (resp_flags & KG2_RESP_FLAG_DELEG_OK) + ctx->gss_flags |= GSS_C_DELEG_FLAG; + + /* drop through to ap_rep handling */ + } else { + /* gsskrb5 v1 */ + + if ((err = g_verify_token_header((gss_OID) mech_type, + &(ap_rep.length), + &ptr, KG_TOK_CTX_AP_REP, + input_token->length))) { if (g_verify_token_header((gss_OID) mech_type, &(ap_rep.length), &ptr, KG_TOK_CTX_ERROR, input_token->length) == 0) { - /* Handle a KRB_ERROR message from the server */ + /* Handle a KRB_ERROR message from the server */ - sptr = (char *) ptr; /* PC compiler bug */ - TREAD_STR(sptr, ap_rep.data, ap_rep.length); + sptr = (char *) ptr; /* PC compiler bug */ + TREAD_STR(sptr, ap_rep.data, ap_rep.length); - code = krb5_rd_error(context, &ap_rep, &krb_error); - if (code) - goto fail; - if (krb_error->error) - code = krb_error->error + ERROR_TABLE_BASE_krb5; - else - code = 0; - krb5_free_error(context, krb_error); + code = krb5_rd_error(context, &ap_rep, &krb_error); + if (code) goto fail; + if (krb_error->error) + code = krb_error->error + ERROR_TABLE_BASE_krb5; + else + code = 0; + krb5_free_error(context, krb_error); + goto fail; } else { - *minor_status = err; - return(GSS_S_DEFECTIVE_TOKEN); + *minor_status = 0; + return(GSS_S_DEFECTIVE_TOKEN); } - } + } - sptr = (char *) ptr; /* PC compiler bug */ - TREAD_STR(sptr, ap_rep.data, ap_rep.length); + sptr = (char *) ptr; /* PC compiler bug */ + TREAD_STR(sptr, ap_rep.data, ap_rep.length); + } /* decode the ap_rep */ - if ((code = krb5_rd_rep(context,ctx->auth_context,&ap_rep, + if ((code = krb5_rd_rep(context, ctx->auth_context, &ap_rep, &ap_rep_data))) { - /* - * XXX A hack for backwards compatiblity. - * To be removed in 1999 -- proven - */ - krb5_auth_con_setuseruserkey(context,ctx->auth_context,ctx->subkey); - if ((krb5_rd_rep(context, ctx->auth_context, &ap_rep, - &ap_rep_data))) - goto fail; + /* + * XXX A hack for backwards compatiblity. + * To be removed in 1999 -- proven + */ + krb5_auth_con_setuseruserkey(context, ctx->auth_context, + ctx->subkey); + if ((krb5_rd_rep(context, ctx->auth_context, &ap_rep, + &ap_rep_data))) + goto fail; } /* store away the sequence number */ @@ -593,6 +974,25 @@ krb5_gss_init_sec_context(minor_status, claimant_cred_handle, /* set established */ ctx->established = 1; + if (ctx->gsskrb5_version == 2000) { + gss_buffer_desc mic_data, mic_token; + + /* start with the token id */ + mic_data.value = ptr-2; + /* end before the ap-rep length */ + mic_data.length = ((char*)(ap_rep.data-2)-(char*)(ptr-2)); + + mic_token.length = mic.length; + mic_token.value = mic.data; + + if (GSS_ERROR(major_status = + krb5_gss_verify_mic(minor_status, *context_handle, + &mic_data, &mic_token, NULL))) { + (void)krb5_gss_delete_sec_context(&dummy, context_handle, NULL); + return(major_status); + } + } + /* set returns */ if (time_rec) { @@ -602,7 +1002,7 @@ krb5_gss_init_sec_context(minor_status, claimant_cred_handle, } if (ret_flags) - *ret_flags = KG_IMPLFLAGS(req_flags); + *ret_flags = ctx->gss_flags; if (actual_mech_type) *actual_mech_type = mech_type; @@ -616,8 +1016,8 @@ krb5_gss_init_sec_context(minor_status, claimant_cred_handle, return(GSS_S_COMPLETE); fail: - (void)krb5_gss_delete_sec_context(minor_status, - (gss_ctx_id_t) ctx, NULL); + (void)krb5_gss_delete_sec_context(minor_status, context_handle, NULL); + *minor_status = code; return(GSS_S_FAILURE); } diff --git a/src/lib/gssapi/krb5/inq_cred.c b/src/lib/gssapi/krb5/inq_cred.c index ee5d436c1..c800012c8 100644 --- a/src/lib/gssapi/krb5/inq_cred.c +++ b/src/lib/gssapi/krb5/inq_cred.c @@ -20,6 +20,32 @@ * PERFORMANCE OF THIS SOFTWARE. */ +/* + * Copyright (C) 1998 by the FundsXpress, INC. + * + * All rights reserved. + * + * Export of this software from the United States of America may require + * a specific license from the United States Government. It is the + * responsibility of any person or organization contemplating export to + * obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of FundsXpress. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. FundsXpress makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + #include "gssapiP_krb5.h" OM_uint32 @@ -39,6 +65,7 @@ krb5_gss_inquire_cred(minor_status, cred_handle, name, lifetime_ret, krb5_deltat lifetime; krb5_principal ret_name; gss_OID_set mechs; + OM_uint32 ret; if (GSS_ERROR(kg_get_context(minor_status, &context))) return(GSS_S_FAILURE); @@ -84,12 +111,26 @@ krb5_gss_inquire_cred(minor_status, cred_handle, name, lifetime_ret, } } - if (mechanisms) - if (! g_copy_OID_set(cred->actual_mechs, &mechs)) { - krb5_free_principal(context, ret_name); - *minor_status = ENOMEM; - return(GSS_S_FAILURE); - } + if (mechanisms) { + if (GSS_ERROR(ret = generic_gss_create_empty_oid_set(minor_status, + &mechs)) || + (cred->prerfc_mech && + GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status, + gss_mech_krb5_old, + &mechs))) || + (cred->rfc_mech && + GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status, + gss_mech_krb5, + &mechs))) || + (cred->rfcv2_mech && + GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status, + gss_mech_krb5_v2, + &mechs)))) { + krb5_free_principal(context, ret_name); + /* *minor_status set above */ + return(ret); + } + } if (name) { if (! kg_save_name((gss_name_t) ret_name)) { @@ -139,7 +180,9 @@ krb5_gss_inquire_cred_by_mech(minor_status, cred_handle, * We only know how to handle our own creds. */ if ((mech_type != GSS_C_NULL_OID) && - !g_OID_equal(gss_mech_krb5, mech_type)) { + !g_OID_equal(gss_mech_krb5_old, mech_type) && + !g_OID_equal(gss_mech_krb5, mech_type) && + !g_OID_equal(gss_mech_krb5_v2, mech_type)) { *minor_status = 0; return(GSS_S_NO_CRED); } diff --git a/src/lib/gssapi/krb5/inq_names.c b/src/lib/gssapi/krb5/inq_names.c index 9c5f47450..01a199430 100644 --- a/src/lib/gssapi/krb5/inq_names.c +++ b/src/lib/gssapi/krb5/inq_names.c @@ -43,10 +43,11 @@ krb5_gss_inquire_names_for_mech(minor_status, mechanism, name_types) * We only know how to handle our own mechanism. */ if ((mechanism != GSS_C_NULL_OID) && + !g_OID_equal(gss_mech_krb5_v2, mechanism) && !g_OID_equal(gss_mech_krb5, mechanism) && !g_OID_equal(gss_mech_krb5_old, mechanism)) { *minor_status = 0; - return(GSS_S_FAILURE); + return(GSS_S_BAD_MECH); } /* We're okay. Create an empty OID set */ diff --git a/src/lib/gssapi/krb5/k5seal.c b/src/lib/gssapi/krb5/k5seal.c index c174bb7cb..e1877b71f 100644 --- a/src/lib/gssapi/krb5/k5seal.c +++ b/src/lib/gssapi/krb5/k5seal.c @@ -20,15 +20,269 @@ * PERFORMANCE OF THIS SOFTWARE. */ +/* + * Copyright (C) 1998 by the FundsXpress, INC. + * + * All rights reserved. + * + * Export of this software from the United States of America may require + * a specific license from the United States Government. It is the + * responsibility of any person or organization contemplating export to + * obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of FundsXpress. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. FundsXpress makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + #include "gssapiP_krb5.h" static krb5_error_code -make_seal_token(context, enc_ed, seq_ed, seqnum, direction, text, token, - signalg, cksum_size, sealalg, encrypt, toktype, - bigend, oid) +make_priv_token_v2 PROTOTYPE((krb5_context context, + krb5_keyblock *subkey, + krb5_int32 *seqnum, + int direction, + gss_buffer_t text, + gss_buffer_t token, + gss_OID oid)); + +static krb5_error_code +make_priv_token_v2(context, subkey, seqnum, direction, text, token, oid) krb5_context context; - krb5_gss_enc_desc *enc_ed; - krb5_gss_enc_desc *seq_ed; + krb5_keyblock *subkey; + krb5_int32 *seqnum; + int direction; + gss_buffer_t text; + gss_buffer_t token; + gss_OID oid; +{ + krb5_data plain; + krb5_enc_data cipher; + krb5_error_code code; + size_t enclen; + int tlen; + unsigned char *t, *ptr; + + plain.data = 0; + cipher.ciphertext.data = 0; + t = 0; + + plain.length = 7+text->length; + if ((plain.data = (void *) malloc(plain.length)) == NULL) { + code = ENOMEM; + goto cleanup; + } + + plain.data[0] = (*seqnum >> 24) & 0xff; + plain.data[1] = (*seqnum >> 16) & 0xff; + plain.data[2] = (*seqnum >> 8) & 0xff; + plain.data[3] = *seqnum & 0xff; + + plain.data[4] = direction?0:0xff; + + plain.data[5] = (text->length >> 8) & 0xff; + plain.data[6] = text->length & 0xff; + + memcpy(plain.data+7, text->value, text->length); + + if (code = krb5_c_encrypt_length(context, subkey->enctype, + plain.length, &enclen)) + goto cleanup; + + tlen = g_token_size((gss_OID) oid, 2+enclen); + + if ((t = (unsigned char *) xmalloc(tlen)) == NULL) + return(ENOMEM); + + ptr = t; + + g_make_token_header((gss_OID) oid, 2+enclen, &ptr, + KG2_TOK_WRAP_PRIV); + + ptr[0] = (enclen >> 8) & 0xff; + ptr[1] = enclen & 0xff; + + cipher.ciphertext.length = enclen; + cipher.ciphertext.data = ptr+2; + + if (code = krb5_c_encrypt(context, subkey, + KRB5_KEYUSAGE_GSS_TOK_WRAP_PRIV, + 0, &plain, &cipher)) + goto cleanup; + + /* that's it. return the token */ + + (*seqnum)++; + + token->length = tlen; + token->value = (void *) t; + + code = 0; + +cleanup: + if (plain.data) + free(plain.data); + if (code) { + if (t) + free(t); + } + + return(code); +} + +static krb5_error_code +make_integ_token_v2 PROTOTYPE((krb5_context context, + krb5_keyblock *subkey, + krb5_cksumtype ctype, + krb5_int32 *seqnum, + int direction, + gss_buffer_t text, + gss_buffer_t token, + int toktype, + gss_OID oid)); + +static krb5_error_code +make_integ_token_v2(context, subkey, ctype, seqnum, direction, text, token, + toktype, oid) + krb5_context context; + krb5_keyblock *subkey; + krb5_cksumtype ctype; + krb5_int32 *seqnum; + int direction; + gss_buffer_t text; + gss_buffer_t token; + int toktype; + gss_OID oid; +{ + krb5_error_code code; + int tmp, tlen; + unsigned char *t, *ptr; + krb5_data plain; + krb5_checksum cksum; + + plain.data = 0; + t = 0; + cksum.contents = 0; + + /* assemble the checksum buffer and compute the checksum */ + + plain.length = 7+text->length; + + if ((plain.data = (char *) malloc(plain.length)) == NULL) + goto cleanup; + + plain.data[0] = (*seqnum >> 24) & 0xff; + plain.data[1] = (*seqnum >> 16) & 0xff; + plain.data[2] = (*seqnum >> 8) & 0xff; + plain.data[3] = *seqnum & 0xff; + + plain.data[4] = direction?0:0xff; + + plain.data[5] = (text->length >> 8) & 0xff; + plain.data[6] = text->length & 0xff; + + memcpy(plain.data+7, text->value, text->length); + + if (code = krb5_c_make_checksum(context, ctype, subkey, + (toktype == KG2_TOK_WRAP_INTEG)? + KRB5_KEYUSAGE_GSS_TOK_WRAP_INTEG: + KRB5_KEYUSAGE_GSS_TOK_MIC, + &plain, &cksum)) + goto cleanup; + + /* assemble the token itself */ + + if (toktype == KG2_TOK_WRAP_INTEG) + tmp = 4+(7+text->length)+2+cksum.length; + else + tmp = 4+(5)+2+cksum.length; + + tlen = g_token_size((gss_OID) oid, tmp); + + if ((t = (unsigned char *) xmalloc(tlen)) == NULL) + return(ENOMEM); + + ptr = t; + + g_make_token_header((gss_OID) oid, tmp, &ptr, toktype); + + ptr[0] = (ctype >> 24) & 0xff; + ptr[1] = (ctype >> 16) & 0xff; + ptr[2] = (ctype >> 8) & 0xff; + ptr[3] = ctype & 0xff; + + ptr += 4; + + if (toktype == KG2_TOK_WRAP_INTEG) { + memcpy(ptr, plain.data, 7+text->length); + ptr += 7+text->length; + } else { + memcpy(ptr, plain.data, 5); + ptr += 5; + } + + ptr[0] = (cksum.length >> 8) & 0xff; + ptr[1] = cksum.length & 0xff; + ptr += 2; + + memcpy(ptr, cksum.contents, cksum.length); + + /* that's it. return the token */ + + (*seqnum)++; + + token->length = tlen; + token->value = (void *) t; + + code = 0; + +cleanup: + if (plain.data) + free(plain.data); + if (cksum.contents) + krb5_free_checksum_contents(context, &cksum); + if (code) { + if (t) + free(t); + } + + return(code); +} + +static krb5_error_code +make_seal_token_v1 PROTOTYPE((krb5_context context, + krb5_keyblock *enc, + krb5_keyblock *seq, + krb5_int32 *seqnum, + int direction, + gss_buffer_t text, + gss_buffer_t token, + int signalg, + int cksum_size, + int sealalg, + int encrypt, + int toktype, + int bigend, + gss_OID oid)); + +static krb5_error_code +make_seal_token_v1(context, enc, seq, seqnum, direction, text, token, + signalg, cksum_size, sealalg, encrypt, toktype, + bigend, oid) + krb5_context context; + krb5_keyblock *enc; + krb5_keyblock *seq; krb5_int32 *seqnum; int direction; gss_buffer_t text; @@ -42,7 +296,9 @@ make_seal_token(context, enc_ed, seq_ed, seqnum, direction, text, token, gss_OID oid; { krb5_error_code code; + size_t sumlen; char *data_ptr; + krb5_data plaind; krb5_checksum md5cksum; krb5_checksum cksum; int conflen=0, tmsglen, tlen; @@ -54,7 +310,7 @@ make_seal_token(context, enc_ed, seq_ed, seqnum, direction, text, token, if (bigend && !encrypt) { tmsglen = text->length; } else { - conflen = kg_confounder_size(enc_ed); + conflen = kg_confounder_size(context, enc); /* XXX knows that des block size is 8 */ tmsglen = (conflen+text->length+8)&(~7); } @@ -96,27 +352,24 @@ make_seal_token(context, enc_ed, seq_ed, seqnum, direction, text, token, /* pad the plaintext, encrypt if needed, and stick it in the token */ - /* initialize the the cksum and allocate the contents buffer */ + /* initialize the the cksum */ + if (code = krb5_c_checksum_length(context, CKSUMTYPE_RSA_MD5, &sumlen)) + return(code); + md5cksum.checksum_type = CKSUMTYPE_RSA_MD5; - md5cksum.length = krb5_checksum_size(context, CKSUMTYPE_RSA_MD5); - if ((md5cksum.contents = (krb5_octet *) xmalloc(md5cksum.length)) == NULL) { - return(ENOMEM); - } - + md5cksum.length = sumlen; if (toktype == KG_TOK_SEAL_MSG) { unsigned char *plain; unsigned char pad; if (!bigend || encrypt) { if ((plain = (unsigned char *) xmalloc(tmsglen)) == NULL) { - xfree(md5cksum.contents); xfree(t); return(ENOMEM); } - if ((code = kg_make_confounder(enc_ed, plain))) { + if ((code = kg_make_confounder(context, enc, plain))) { xfree(plain); - xfree(md5cksum.contents); xfree(t); return(code); } @@ -133,12 +386,11 @@ make_seal_token(context, enc_ed, seq_ed, seqnum, direction, text, token, } if (encrypt) { - if ((code = kg_encrypt(context, enc_ed, NULL, (krb5_pointer) plain, + if ((code = kg_encrypt(context, enc, NULL, (krb5_pointer) plain, (krb5_pointer) (ptr+cksum_size+14), tmsglen))) { if (plain) xfree(plain); - xfree(md5cksum.contents); xfree(t); return(code); } @@ -156,7 +408,6 @@ make_seal_token(context, enc_ed, seq_ed, seqnum, direction, text, token, (char *) xmalloc(8 + (bigend ? text->length : tmsglen)))) { if (plain) xfree(plain); - xfree(md5cksum.contents); xfree(t); return(ENOMEM); } @@ -165,15 +416,15 @@ make_seal_token(context, enc_ed, seq_ed, seqnum, direction, text, token, (void) memcpy(data_ptr+8, text->value, text->length); else (void) memcpy(data_ptr+8, plain, tmsglen); - code = krb5_calculate_checksum(context, md5cksum.checksum_type, data_ptr, - 8 + (bigend ? text->length : tmsglen), - 0, 0, &md5cksum); + plaind.length = 8 + (bigend ? text->length : tmsglen); + plaind.data = data_ptr; + code = krb5_c_make_checksum(context, md5cksum.checksum_type, + 0, 0, &plaind, &md5cksum); xfree(data_ptr); if (code) { if (plain) xfree(plain); - xfree(md5cksum.contents); xfree(t); return(code); memcpy(ptr+14+cksum_size, plain, tmsglen); @@ -185,18 +436,17 @@ make_seal_token(context, enc_ed, seq_ed, seqnum, direction, text, token, /* compute the checksum */ if (! (data_ptr = (char *) xmalloc(8 + text->length))) { - xfree(md5cksum.contents); xfree(t); return(ENOMEM); } (void) memcpy(data_ptr, ptr-2, 8); (void) memcpy(data_ptr+8, text->value, text->length); - code = krb5_calculate_checksum(context, md5cksum.checksum_type, data_ptr, - 8 + text->length, - 0, 0, &md5cksum); + plaind.length = 8 + text->length; + plaind.data = data_ptr; + code = krb5_c_make_checksum(context, md5cksum.checksum_type, 0, 0, + &plaind, &md5cksum); xfree(data_ptr); if (code) { - xfree(md5cksum.contents); xfree(t); return(code); } @@ -214,16 +464,19 @@ make_seal_token(context, enc_ed, seq_ed, seqnum, direction, text, token, DES encryption the long way, and keep the last block as the MAC */ + /* XXX not converted to new api since it's inside an #if 0 */ + /* initialize the the cksum and allocate the contents buffer */ cksum.checksum_type = CKSUMTYPE_DESCBC; cksum.length = krb5_checksum_size(context, CKSUMTYPE_DESCBC); if ((cksum.contents = (krb5_octet *) xmalloc(cksum.length)) == NULL) return(ENOMEM); + /* XXX not converted to new api since it's inside an #if 0 */ if (code = krb5_calculate_checksum(context, cksum.checksum_type, md5cksum.contents, 16, - seq_ed->key->contents, - seq_ed->key->length, + seq->contents, + seq->length, &cksum)) { xfree(cksum.contents); xfree(md5cksum.contents); @@ -235,9 +488,9 @@ make_seal_token(context, enc_ed, seq_ed, seqnum, direction, text, token, xfree(cksum.contents); #else - if ((code = kg_encrypt(context, seq_ed, + if ((code = kg_encrypt(context, seq, (g_OID_equal(oid, gss_mech_krb5_old) ? - seq_ed->key->contents : NULL), + seq->contents : NULL), md5cksum.contents, md5cksum.contents, 16))) { xfree(md5cksum.contents); xfree(t); @@ -257,7 +510,7 @@ make_seal_token(context, enc_ed, seq_ed, seqnum, direction, text, token, /* create the seq_num */ - if ((code = kg_make_seq_num(context, seq_ed, direction?0:0xff, *seqnum, + if ((code = kg_make_seq_num(context, seq, direction?0:0xff, *seqnum, ptr+14, ptr+6))) { xfree(t); return(code); @@ -320,17 +573,42 @@ kg_seal(context, minor_status, context_handle, conf_req_flag, qop_req, return(GSS_S_FAILURE); } - if ((code = make_seal_token(context, &ctx->enc, &ctx->seq, - &ctx->seq_send, ctx->initiate, - input_message_buffer, output_message_buffer, - ctx->signalg, ctx->cksum_size, ctx->sealalg, - conf_req_flag, toktype, ctx->big_endian, - ctx->mech_used))) { + if (ctx->gsskrb5_version == 2000) { + if (toktype == KG_TOK_WRAP_MSG) { + if (conf_req_flag) + toktype = KG2_TOK_WRAP_PRIV; + else + toktype = KG2_TOK_WRAP_INTEG; + } else { + toktype = KG2_TOK_MIC; + } + + if (conf_req_flag) { + code = make_priv_token_v2(context, ctx->subkey, &ctx->seq_send, + ctx->initiate, input_message_buffer, + output_message_buffer, ctx->mech_used); + } else { + code = make_integ_token_v2(context, ctx->subkey, ctx->ctypes[0], + &ctx->seq_send, ctx->initiate, + input_message_buffer, + output_message_buffer, toktype, + ctx->mech_used); + } + } else { + code = make_seal_token_v1(context, ctx->enc, ctx->seq, + &ctx->seq_send, ctx->initiate, + input_message_buffer, output_message_buffer, + ctx->signalg, ctx->cksum_size, ctx->sealalg, + conf_req_flag, toktype, ctx->big_endian, + ctx->mech_used); + } + + if (code) { *minor_status = code; return(GSS_S_FAILURE); } - if ((toktype == KG_TOK_SEAL_MSG) && conf_state) + if (conf_state) *conf_state = conf_req_flag; *minor_status = 0; diff --git a/src/lib/gssapi/krb5/k5unseal.c b/src/lib/gssapi/krb5/k5unseal.c index 041cae06a..c32e3255d 100644 --- a/src/lib/gssapi/krb5/k5unseal.c +++ b/src/lib/gssapi/krb5/k5unseal.c @@ -20,6 +20,32 @@ * PERFORMANCE OF THIS SOFTWARE. */ +/* + * Copyright (C) 1998 by the FundsXpress, INC. + * + * All rights reserved. + * + * Export of this software from the United States of America may require + * a specific license from the United States Government. It is the + * responsibility of any person or organization contemplating export to + * obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of FundsXpress. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. FundsXpress makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + #include "gssapiP_krb5.h" #include <memory.h> @@ -27,34 +53,417 @@ * $Id$ */ +static OM_uint32 +kg2_verify_mic(context, minor_status, ctx, ptr, bodysize, + text, qop_state) + krb5_context context; + OM_uint32 *minor_status; + krb5_gss_ctx_id_rec *ctx; + unsigned char *ptr; + int bodysize; + gss_buffer_t text; + gss_qop_t *qop_state; +{ + size_t cksumlen; + krb5_error_code code; + krb5_data plain; + krb5_cksumtype tctype; + krb5_ui_4 tseqnum; + int tdirection; + krb5_checksum cksum; + krb5_boolean ckvalid; + krb5_timestamp now; + OM_uint32 retval; + + plain.data = 0; + cksum.contents = 0; + + /* verify the header */ + + if (bodysize < 11) { + free(plain.data); + *minor_status = G_TOK_TRUNC; + return(GSS_S_DEFECTIVE_TOKEN); + } + + /* allocate the checksum buffer */ + + plain.length = 7+text->length; + + if ((plain.data = (char *) malloc(plain.length)) == NULL) { + *minor_status = ENOMEM; + return(GSS_S_FAILURE); + } + + /* suck out the body parts from the token */ + + tctype = (krb5_cksumtype) ((ptr[0]<<24) | (ptr[1]<<16) | + (ptr[2]<<8) | ptr[3]); + ptr += 4; + + memcpy(plain.data, ptr, 5); + tseqnum = ((ptr[0]<<24) | (ptr[1]<<16) | (ptr[2]<<8) | ptr[3]); + ptr += 4; + tdirection = ptr[0]; + ptr += 1; + + cksum.length = (ptr[0]<<8) | ptr[1]; + ptr += 2; + bodysize -= 11; + + if (cksum.length != bodysize) { + free(plain.data); + *minor_status = G_TOK_TRUNC; + return(GSS_S_DEFECTIVE_TOKEN); + } + + cksum.contents = ptr; + cksum.checksum_type = tctype; + + /* finish assembling the checksum buffer and compute the checksum */ + + plain.data[5] = (text->length >> 8) & 0xff; + plain.data[6] = text->length & 0xff; + + memcpy(plain.data+7, text->value, text->length); + + if (code = krb5_c_verify_checksum(context, ctx->subkey, + KRB5_KEYUSAGE_GSS_TOK_MIC, + &plain, &cksum, &ckvalid)) { + free(plain.data); + *minor_status = code; + return(GSS_S_FAILURE); + } + + if (!ckvalid) { + free(plain.data); + *minor_status = 0; + return(GSS_S_BAD_SIG); + } + + /* check context expiry */ + + if ((code = krb5_timeofday(context, &now))) { + free(plain.data); + *minor_status = code; + return(GSS_S_FAILURE); + } + + if (now > ctx->endtime) { + free(plain.data); + *minor_status = 0; + return(GSS_S_CONTEXT_EXPIRED); + } + + /* do sequencing checks */ + + if ((ctx->initiate && tdirection != 0xff) || + (!ctx->initiate && tdirection != 0)) { + free(plain.data); + *minor_status = G_BAD_DIRECTION; + return(GSS_S_BAD_SIG); + } + + retval = g_order_check(&(ctx->seqstate), tseqnum); + + free(plain.data); + + if (retval) { + *minor_status = 0; + return(retval); + } + + if (qop_state) + *qop_state = GSS_C_QOP_DEFAULT; + + *minor_status = 0; + return(GSS_S_COMPLETE); +} + +static OM_uint32 +kg2_unwrap_integ(context, minor_status, ctx, ptr, bodysize, output, qop_state) + krb5_context context; + OM_uint32 *minor_status; + krb5_gss_ctx_id_rec *ctx; + unsigned char *ptr; + int bodysize; + gss_buffer_t output; + gss_qop_t *qop_state; +{ + krb5_error_code code; + OM_uint32 retval; + krb5_ui_4 tseqnum; + int tdirection; + int tmsglen; + unsigned char *tmsg; + krb5_data plain; + krb5_checksum tcksum; + krb5_boolean ckvalid; + krb5_timestamp now; + + output->length = 0; + output->value = NULL; + + /* read the body parts out of the message */ + + if (bodysize < 11) { + *minor_status = G_TOK_TRUNC; + return(GSS_S_DEFECTIVE_TOKEN); + } + + tcksum.checksum_type = (krb5_cksumtype) ((ptr[0]<<24) | (ptr[1]<<16) | + (ptr[2]<<8) | ptr[3]); + ptr += 4; + + plain.data = ptr; + + tseqnum = ((ptr[0]<<24) | (ptr[1]<<16) | (ptr[2]<<8) | ptr[3]); + ptr += 4; + tdirection = ptr[0]; + ptr += 1; + + tmsglen = (ptr[0]<<8) | ptr[1]; + ptr += 2; + bodysize -= 11; + + if (bodysize < tmsglen) { + *minor_status = G_TOK_TRUNC; + return(GSS_S_DEFECTIVE_TOKEN); + } + + tmsg = ptr; + ptr += tmsglen; + bodysize -= tmsglen; + + plain.length = ((char*)ptr) - ((char *)plain.data); + + tcksum.length = (ptr[0]<<8) | ptr[1]; + ptr += 2; + bodysize -= 2; + + if (bodysize != tcksum.length) { + *minor_status = G_TOK_TRUNC; + return(GSS_S_DEFECTIVE_TOKEN); + } + + tcksum.contents = ptr; + + /* verify the MIC */ + + if (code = krb5_c_verify_checksum(context, ctx->subkey, + KRB5_KEYUSAGE_GSS_TOK_WRAP_INTEG, + &plain, &tcksum, &ckvalid)) { + *minor_status = code; + return(GSS_S_FAILURE); + } + + if (!ckvalid) { + *minor_status = 0; + return(GSS_S_BAD_SIG); + } + + /* check context expiry */ + + if ((code = krb5_timeofday(context, &now))) { + *minor_status = code; + return(GSS_S_FAILURE); + } + + if (now > ctx->endtime) { + *minor_status = 0; + return(GSS_S_CONTEXT_EXPIRED); + } + + /* do sequencing checks */ + + if ((ctx->initiate && tdirection != 0xff) || + (!ctx->initiate && tdirection != 0)) { + *minor_status = G_BAD_DIRECTION; + return(GSS_S_BAD_SIG); + } + + if (retval = g_order_check(&(ctx->seqstate), tseqnum)) { + *minor_status = 0; + return(retval); + } + + if ((output->value = (void *) malloc(tmsglen)) == NULL) { + *minor_status = ENOMEM; + return(GSS_S_FAILURE); + } + + memcpy(output->value, tmsg, tmsglen); + output->length = tmsglen; + + if (qop_state) + *qop_state = GSS_C_QOP_DEFAULT; + + *minor_status = 0; + return(GSS_S_COMPLETE); +} + +static OM_uint32 +kg2_unwrap_priv(context, minor_status, ctx, ptr, bodysize, output, qop_state) + krb5_context context; + OM_uint32 *minor_status; + krb5_gss_ctx_id_rec *ctx; + unsigned char *ptr; + int bodysize; + gss_buffer_t output; + gss_qop_t *qop_state; +{ + krb5_error_code code; + OM_uint32 retval; + krb5_enc_data cipher; + krb5_data plain; + krb5_ui_4 tseqnum; + int tdirection; + int tmsglen; + unsigned char *tmsg; + krb5_timestamp now; + + output->length = 0; + output->value = NULL; + + /* read the body parts out of the message */ + + if (bodysize < 2) { + *minor_status = G_TOK_TRUNC; + return(GSS_S_DEFECTIVE_TOKEN); + } + + cipher.ciphertext.length = (ptr[0]<<8) | ptr[1]; + ptr += 2; + bodysize -= 2; + + if (bodysize != cipher.ciphertext.length) { + *minor_status = G_TOK_TRUNC; + return(GSS_S_DEFECTIVE_TOKEN); + } + + cipher.ciphertext.data = ptr; + cipher.enctype = ENCTYPE_UNKNOWN; + + plain.length = cipher.ciphertext.length; + if ((plain.data = (char *) malloc(plain.length)) == NULL) { + *minor_status = 0; + return(GSS_S_FAILURE); + } + + /* decrypt (and implicitly verify) the encrypted data */ + + if (code = krb5_c_decrypt(context, ctx->subkey, + KRB5_KEYUSAGE_GSS_TOK_WRAP_PRIV, + 0, &cipher, &plain)) { + free(plain.data); + *minor_status = code; + return(GSS_S_FAILURE); + } + + /* parse out the encrypted fields */ + + ptr = plain.data; + bodysize = plain.length; + + if (bodysize < 7) { + free(plain.data); + *minor_status = G_TOK_TRUNC; + return(GSS_S_DEFECTIVE_TOKEN); + } + + tseqnum = ((ptr[0]<<24) | (ptr[1]<<16) | (ptr[2]<<8) | ptr[3]); + ptr += 4; + tdirection = ptr[0]; + ptr += 1; + + tmsglen = (ptr[0]<<8) | ptr[1]; + ptr += 2; + bodysize -= 7; + + /* check context expiry */ + + if ((code = krb5_timeofday(context, &now))) { + free(plain.data); + *minor_status = code; + return(GSS_S_FAILURE); + } + + if (now > ctx->endtime) { + free(plain.data); + *minor_status = 0; + return(GSS_S_CONTEXT_EXPIRED); + } + + /* do sequencing checks */ + + if ((ctx->initiate && tdirection != 0xff) || + (!ctx->initiate && tdirection != 0)) { + free(plain.data); + *minor_status = G_BAD_DIRECTION; + return(GSS_S_BAD_SIG); + } + + if (retval = g_order_check(&(ctx->seqstate), tseqnum)) { + free(plain.data); + *minor_status = 0; + return(retval); + } + + /* now copy out the data. can't do a strict equality check here, + since the output could be padded. */ + + if (bodysize < tmsglen) { + free(plain.data); + *minor_status = G_TOK_TRUNC; + return(GSS_S_DEFECTIVE_TOKEN); + } + + tmsg = ptr; + + if ((output->value = (void *) malloc(tmsglen)) == NULL) { + free(plain.data); + *minor_status = ENOMEM; + return(GSS_S_FAILURE); + } + + memcpy(output->value, tmsg, tmsglen); + output->length = tmsglen; + + if (qop_state) + *qop_state = GSS_C_QOP_DEFAULT; + + free(plain.data); + + *minor_status = 0; + return(GSS_S_COMPLETE); +} + /* message_buffer is an input if SIGN, output if SEAL, and ignored if DEL_CTX - conf_state is only valid if SEAL. - */ + conf_state is only valid if SEAL. */ OM_uint32 -kg_unseal(context, minor_status, context_handle, input_token_buffer, - message_buffer, conf_state, qop_state, toktype) +kg_unseal_v1(context, minor_status, ctx, ptr, bodysize, message_buffer, + conf_state, qop_state, toktype) krb5_context context; OM_uint32 *minor_status; - gss_ctx_id_t context_handle; - gss_buffer_t input_token_buffer; + krb5_gss_ctx_id_rec *ctx; + unsigned char *ptr; + int bodysize; gss_buffer_t message_buffer; int *conf_state; int *qop_state; int toktype; { - krb5_gss_ctx_id_rec *ctx; krb5_error_code code; - int bodysize; int tmsglen; int conflen = 0; int signalg; int sealalg; gss_buffer_desc token; - unsigned char *ptr; krb5_checksum cksum; krb5_checksum desmac; krb5_checksum md5cksum; + krb5_data plaind; char *data_ptr; krb5_timestamp now; unsigned char *plain; @@ -64,38 +473,13 @@ kg_unseal(context, minor_status, context_handle, input_token_buffer, int direction; krb5_int32 seqnum; OM_uint32 retval; + size_t sumlen; if (toktype == KG_TOK_SEAL_MSG) { message_buffer->length = 0; message_buffer->value = NULL; } - /* validate the context handle */ - if (! kg_validate_ctx_id(context_handle)) { - *minor_status = (OM_uint32) G_VALIDATE_FAILED; - return(GSS_S_NO_CONTEXT); - } - - ctx = (krb5_gss_ctx_id_rec *) context_handle; - - if (! ctx->established) { - *minor_status = KG_CTX_INCOMPLETE; - return(GSS_S_NO_CONTEXT); - } - - /* parse the token, leave the data in message_buffer, setting conf_state */ - - /* verify the header */ - - ptr = (unsigned char *) input_token_buffer->value; - - if ((err = g_verify_token_header((gss_OID) ctx->mech_used, &bodysize, - &ptr, toktype, - input_token_buffer->length))) { - *minor_status = err; - return(GSS_S_DEFECTIVE_TOKEN); - } - /* get the sign and seal algorithms */ signalg = ptr[0] + (ptr[1]<<8); @@ -159,7 +543,7 @@ kg_unseal(context, minor_status, context_handle, input_token_buffer, return(GSS_S_FAILURE); } - if ((code = kg_decrypt(context, &ctx->enc, NULL, + if ((code = kg_decrypt(context, ctx->enc, NULL, ptr+14+cksum_len, plain, tmsglen))) { xfree(plain); *minor_status = code; @@ -174,7 +558,7 @@ kg_unseal(context, minor_status, context_handle, input_token_buffer, if ((sealalg == 0xffff) && ctx->big_endian) { token.length = tmsglen; } else { - conflen = kg_confounder_size(&ctx->enc); + conflen = kg_confounder_size(context, ctx->enc); token.length = tmsglen - conflen - plain[tmsglen-1]; } @@ -200,15 +584,12 @@ kg_unseal(context, minor_status, context_handle, input_token_buffer, /* compute the checksum of the message */ - /* initialize the the cksum and allocate the contents buffer */ + /* initialize the the cksum */ + if (code = krb5_c_checksum_length(context, CKSUMTYPE_RSA_MD5, &sumlen)) + return(code); + md5cksum.checksum_type = CKSUMTYPE_RSA_MD5; - md5cksum.length = krb5_checksum_size(context, CKSUMTYPE_RSA_MD5); - if ((md5cksum.contents = (krb5_octet *) xmalloc(md5cksum.length)) == NULL) { - if (sealalg != 0xffff) - xfree(plain); - *minor_status = ENOMEM; - return(GSS_S_FAILURE); - } + md5cksum.length = sumlen; switch (signalg) { case 0: @@ -219,7 +600,6 @@ kg_unseal(context, minor_status, context_handle, input_token_buffer, if (! (data_ptr = (void *) xmalloc(8 + (ctx->big_endian ? token.length : plainlen)))) { - xfree(md5cksum.contents); if (sealalg != 0xffff) xfree(plain); if (toktype == KG_TOK_SEAL_MSG) @@ -235,14 +615,13 @@ kg_unseal(context, minor_status, context_handle, input_token_buffer, else (void) memcpy(data_ptr+8, plain, plainlen); - code = krb5_calculate_checksum(context, md5cksum.checksum_type, - data_ptr, 8 + - (ctx->big_endian ? token.length : - plainlen), 0, 0, &md5cksum); + plaind.length = 8 + (ctx->big_endian ? token.length : plainlen); + plaind.data = data_ptr; + code = krb5_c_make_checksum(context, md5cksum.checksum_type, 0, 0, + &plaind, &md5cksum); xfree(data_ptr); if (code) { - xfree(md5cksum.contents); if (toktype == KG_TOK_SEAL_MSG) xfree(token.value); *minor_status = code; @@ -264,6 +643,7 @@ kg_unseal(context, minor_status, context_handle, input_token_buffer, return(GSS_S_FAILURE); } + /* XXX not converted to new api since it's inside an #if 0 */ if (code = krb5_calculate_checksum(context, cksum.checksum_type, md5cksum.contents, 16, ctx->seq.key->contents, @@ -281,9 +661,9 @@ kg_unseal(context, minor_status, context_handle, input_token_buffer, xfree(cksum.contents); #else - if ((code = kg_encrypt(context, &ctx->seq, + if ((code = kg_encrypt(context, ctx->seq, (g_OID_equal(ctx->mech_used, gss_mech_krb5_old) ? - ctx->seq.key->contents : NULL), + ctx->seq->contents : NULL), md5cksum.contents, md5cksum.contents, 16))) { xfree(md5cksum.contents); if (toktype == KG_TOK_SEAL_MSG) @@ -333,15 +713,15 @@ kg_unseal(context, minor_status, context_handle, input_token_buffer, else (void) memcpy(data_ptr+8+sizeof(ctx->seed), plain, plainlen); - code = krb5_calculate_checksum(context, md5cksum.checksum_type, - data_ptr, 8 + sizeof(ctx->seed) + - (ctx->big_endian ? token.length : - plainlen), 0, 0, &md5cksum); - + plaind.length = 8 + sizeof(ctx->seed) + + (ctx->big_endian ? token.length : plainlen); + plaind.data = data_ptr; + xfree(md5cksum.contents); + code = krb5_c_make_checksum(context, md5cksum.checksum_type, 0, 0, + &plaind, &md5cksum); xfree(data_ptr); if (code) { - xfree(md5cksum.contents); if (sealalg == 0) xfree(plain); if (toktype == KG_TOK_SEAL_MSG) @@ -394,7 +774,7 @@ kg_unseal(context, minor_status, context_handle, input_token_buffer, /* do sequencing checks */ - if ((code = kg_get_seq_num(context, &(ctx->seq), ptr+14, ptr+6, &direction, + if ((code = kg_get_seq_num(context, ctx->seq, ptr+14, ptr+6, &direction, &seqnum))) { if (toktype == KG_TOK_SEAL_MSG) xfree(token.value); @@ -417,3 +797,88 @@ kg_unseal(context, minor_status, context_handle, input_token_buffer, *minor_status = 0; return(retval); } + +/* message_buffer is an input if SIGN, output if SEAL, and ignored if DEL_CTX + conf_state is only valid if SEAL. */ + +OM_uint32 +kg_unseal(context, minor_status, context_handle, input_token_buffer, + message_buffer, conf_state, qop_state, toktype) + krb5_context context; + OM_uint32 *minor_status; + gss_ctx_id_t context_handle; + gss_buffer_t input_token_buffer; + gss_buffer_t message_buffer; + int *conf_state; + int *qop_state; + int toktype; +{ + krb5_gss_ctx_id_rec *ctx; + unsigned char *ptr; + int bodysize; + int err; + OM_uint32 retval; + + /* validate the context handle */ + if (! kg_validate_ctx_id(context_handle)) { + *minor_status = (OM_uint32) G_VALIDATE_FAILED; + return(GSS_S_NO_CONTEXT); + } + + ctx = (krb5_gss_ctx_id_rec *) context_handle; + + if (! ctx->established) { + *minor_status = KG_CTX_INCOMPLETE; + return(GSS_S_NO_CONTEXT); + } + + /* parse the token, leave the data in message_buffer, setting conf_state */ + + /* verify the header */ + + ptr = (unsigned char *) input_token_buffer->value; + + if (ctx->gsskrb5_version == 2000) { + if (!(err = g_verify_token_header((gss_OID) ctx->mech_used, + &bodysize, &ptr, KG2_TOK_MIC, + input_token_buffer->length))) { + return(kg2_verify_mic(context, minor_status, ctx, ptr, bodysize, + message_buffer, qop_state)); + } else if (!(err = g_verify_token_header((gss_OID) ctx->mech_used, + &bodysize, &ptr, + KG2_TOK_WRAP_INTEG, + input_token_buffer->length))) { + if (GSS_ERROR(retval = kg2_unwrap_integ(context, minor_status, + ctx, ptr, bodysize, + message_buffer, qop_state))) + return(retval); + + if (conf_state) + *conf_state = 0; + return(GSS_S_COMPLETE); + } else if (!(err = g_verify_token_header((gss_OID) ctx->mech_used, + &bodysize, &ptr, + KG2_TOK_WRAP_PRIV, + input_token_buffer->length))) { + if (GSS_ERROR(retval = kg2_unwrap_priv(context, minor_status, + ctx, ptr, bodysize, + message_buffer, qop_state))) + return(retval); + + if (conf_state) + *conf_state = 1; + return(GSS_S_COMPLETE); + } + } else { + if (!(err = g_verify_token_header((gss_OID) ctx->mech_used, + &bodysize, &ptr, toktype, + input_token_buffer->length))) { + return(kg_unseal_v1(context, minor_status, ctx, ptr, bodysize, + message_buffer, conf_state, qop_state, + toktype)); + } + } + + *minor_status = err; + return(GSS_S_DEFECTIVE_TOKEN); +} diff --git a/src/lib/gssapi/krb5/rel_oid.c b/src/lib/gssapi/krb5/rel_oid.c index f35727e3f..afb2171b8 100644 --- a/src/lib/gssapi/krb5/rel_oid.c +++ b/src/lib/gssapi/krb5/rel_oid.c @@ -63,7 +63,8 @@ krb5_gss_internal_release_oid(minor_status, oid) * return GSS_S_CONTINUE_NEEDED for any OIDs it does not recognize. */ - if ((*oid != gss_mech_krb5) && + if ((*oid != gss_mech_krb5_v2) && + (*oid != gss_mech_krb5) && (*oid != gss_mech_krb5_old) && (*oid != gss_nt_krb5_name) && (*oid != gss_nt_krb5_principal)) { diff --git a/src/lib/gssapi/krb5/ser_sctx.c b/src/lib/gssapi/krb5/ser_sctx.c index 36e70d742..36a16d426 100644 --- a/src/lib/gssapi/krb5/ser_sctx.c +++ b/src/lib/gssapi/krb5/ser_sctx.c @@ -40,192 +40,6 @@ * still be done. --marc */ -/* - * Determine the size required for this krb5_gss_enc_desc. - */ -static krb5_error_code -kg_enc_desc_size(kcontext, arg, sizep) - krb5_context kcontext; - krb5_pointer arg; - size_t *sizep; -{ - krb5_error_code kret; - krb5_gss_enc_desc *edescp; - size_t required; - - /* - * krb5_gss_cred_id_t requires: - * krb5_int32 for KG_ENC_DESC - * krb5_int32 for processed. - * krb5_int32 for trailer. - */ - kret = EINVAL; - if ((edescp = (krb5_gss_enc_desc *) arg)) { - required = 3*sizeof(krb5_int32); - if (edescp->key) - kret = krb5_size_opaque(kcontext, - KV5M_KEYBLOCK, - (krb5_pointer) edescp->key, - &required); - else - kret = 0; - - /* - * We need to use size_opaque here because we're not sure as to the - * ancestry of this eblock, and we can't be sure that the magic number - * is set in it, so we ASSuME that it's ok. - */ - if (!kret) - kret = krb5_size_opaque(kcontext, - KV5M_ENCRYPT_BLOCK, - (krb5_pointer) &edescp->eblock, - &required); - - if (!kret) - *sizep += required; - } - return(kret); -} - -/* - * Externalize this krb5_gss_enc_desc. - */ -static krb5_error_code -kg_enc_desc_externalize(kcontext, arg, buffer, lenremain) - krb5_context kcontext; - krb5_pointer arg; - krb5_octet **buffer; - size_t *lenremain; -{ - krb5_error_code kret; - krb5_gss_enc_desc *enc_desc; - size_t required; - krb5_octet *bp; - size_t remain; - - required = 0; - bp = *buffer; - remain = *lenremain; - kret = EINVAL; - if ((enc_desc = (krb5_gss_enc_desc *) arg)) { - kret = ENOMEM; - if (!kg_enc_desc_size(kcontext, arg, &required) && - (required <= remain)) { - /* Our identifier */ - (void) krb5_ser_pack_int32(KG_ENC_DESC, &bp, &remain); - - /* Now static data */ - (void) krb5_ser_pack_int32((krb5_int32) enc_desc->processed, - &bp, &remain); - - /* Now pack up dynamic data */ - if (enc_desc->key) - kret = krb5_externalize_opaque(kcontext, - KV5M_KEYBLOCK, - (krb5_pointer) enc_desc->key, - &bp, &remain); - else - kret = 0; - - if (!kret) - kret = krb5_externalize_opaque(kcontext, - KV5M_ENCRYPT_BLOCK, - (krb5_pointer)&enc_desc->eblock, - &bp, &remain); - if (!kret) { - (void) krb5_ser_pack_int32(KG_ENC_DESC, &bp, &remain); - *buffer = bp; - *lenremain = remain; - } - } - } - return(kret); -} - -/* - * Internalize this krb5_gss_enc_desc. - */ -static krb5_error_code -kg_enc_desc_internalize(kcontext, argp, buffer, lenremain) - krb5_context kcontext; - krb5_pointer *argp; - krb5_octet **buffer; - size_t *lenremain; -{ - krb5_error_code kret; - krb5_gss_enc_desc *edescp; - krb5_int32 ibuf; - krb5_octet *bp; - krb5_encrypt_block *eblockp; - size_t remain; - - bp = *buffer; - remain = *lenremain; - kret = EINVAL; - /* Read our magic number */ - if (krb5_ser_unpack_int32(&ibuf, &bp, &remain)) - ibuf = 0; - if (ibuf == KG_ENC_DESC) { - kret = ENOMEM; - - /* Get an enc_desc */ - if ((remain >= (2*sizeof(krb5_int32))) && - (edescp = (krb5_gss_enc_desc *) - xmalloc(sizeof(krb5_gss_enc_desc)))) { - memset(edescp, 0, sizeof(krb5_gss_enc_desc)); - - /* Get the static data */ - (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); - edescp->processed = (int) ibuf; - - /* edescp->key */ - if ((kret = krb5_internalize_opaque(kcontext, - KV5M_KEYBLOCK, - (krb5_pointer *) &edescp->key, - &bp, &remain))) { - if (kret == EINVAL) - kret = 0; - } - - /* edescp->eblock */ - if (!kret && - (kret = krb5_internalize_opaque(kcontext, - KV5M_ENCRYPT_BLOCK, - (krb5_pointer *) &eblockp, - &bp, &remain))) { - if (kret == EINVAL) - kret = 0; - } - else { - /* Successful, copy in allocated eblock to our structure */ - memcpy(&edescp->eblock, eblockp, sizeof(edescp->eblock)); - krb5_xfree(eblockp); - } - - /* trailer */ - if (!kret && - !(kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)) && - (ibuf == KG_ENC_DESC)) { - *buffer = bp; - *lenremain = remain; - *argp = (krb5_pointer) edescp; - } - else { - if (!kret && (ibuf != KG_ENC_DESC)) - kret = EINVAL; - if (edescp->eblock.key) - krb5_free_keyblock(kcontext, edescp->eblock.key); - if (edescp->eblock.priv && edescp->eblock.priv_size) - krb5_xfree(edescp->eblock.priv); - if (edescp->key) - krb5_free_keyblock(kcontext, edescp->key); - xfree(edescp); - } - } - } - return(kret); -} - static krb5_error_code kg_oid_externalize(kcontext, arg, buffer, lenremain) krb5_context kcontext; @@ -416,12 +230,15 @@ kg_ctx_size(kcontext, arg, sizep) * krb5_int32 for seq_recv. * krb5_int32 for established. * krb5_int32 for big_endian. + * krb5_int32 for gsskrb5_version. + * krb5_int32 for nctypes. * krb5_int32 for trailer. */ kret = EINVAL; if ((ctx = (krb5_gss_ctx_id_rec *) arg)) { - required = 14*sizeof(krb5_int32); + required = 16*sizeof(krb5_int32); required += sizeof(ctx->seed); + required += ctx->nctypes*sizeof(krb5_int32); kret = 0; if (!kret && ctx->here) @@ -442,14 +259,16 @@ kg_ctx_size(kcontext, arg, sizep) (krb5_pointer) ctx->subkey, &required); - if (!kret) - kret = kg_enc_desc_size(kcontext, - (krb5_pointer) &ctx->enc, + if (!kret && ctx->enc) + kret = krb5_size_opaque(kcontext, + KV5M_KEYBLOCK, + (krb5_pointer) ctx->enc, &required); - if (!kret) - kret = kg_enc_desc_size(kcontext, - (krb5_pointer) &ctx->seq, + if (!kret && ctx->seq) + kret = krb5_size_opaque(kcontext, + KV5M_KEYBLOCK, + (krb5_pointer) ctx->seq, &required); if (!kret) @@ -486,6 +305,7 @@ kg_ctx_externalize(kcontext, arg, buffer, lenremain) size_t required; krb5_octet *bp; size_t remain; + int i; required = 0; bp = *buffer; @@ -526,6 +346,10 @@ kg_ctx_externalize(kcontext, arg, buffer, lenremain) &bp, &remain); (void) krb5_ser_pack_int32((krb5_int32) ctx->big_endian, &bp, &remain); + (void) krb5_ser_pack_int32((krb5_int32) ctx->gsskrb5_version, + &bp, &remain); + (void) krb5_ser_pack_int32((krb5_int32) ctx->nctypes, + &bp, &remain); /* Now dynamic data */ kret = 0; @@ -552,14 +376,16 @@ kg_ctx_externalize(kcontext, arg, buffer, lenremain) (krb5_pointer) ctx->subkey, &bp, &remain); - if (!kret) - kret = kg_enc_desc_externalize(kcontext, - (krb5_pointer) &ctx->enc, + if (!kret && ctx->enc) + kret = krb5_externalize_opaque(kcontext, + KV5M_KEYBLOCK, + (krb5_pointer) ctx->enc, &bp, &remain); - if (!kret) - kret = kg_enc_desc_externalize(kcontext, - (krb5_pointer) &ctx->seq, + if (!kret && ctx->seq) + kret = krb5_externalize_opaque(kcontext, + KV5M_KEYBLOCK, + (krb5_pointer) ctx->seq, &bp, &remain); if (!kret && ctx->seqstate) @@ -571,6 +397,13 @@ kg_ctx_externalize(kcontext, arg, buffer, lenremain) KV5M_AUTH_CONTEXT, (krb5_pointer) ctx->auth_context, &bp, &remain); + + for (i=0; i<ctx->nctypes; i++) { + if (!kret) { + kret = krb5_ser_pack_int32((krb5_int32) ctx->ctypes[i], + &bp, &remain); + } + } if (!kret) { (void) krb5_ser_pack_int32(KG_CONTEXT, &bp, &remain); @@ -597,7 +430,7 @@ kg_ctx_internalize(kcontext, argp, buffer, lenremain) krb5_int32 ibuf; krb5_octet *bp; size_t remain; - krb5_gss_enc_desc *edp; + int i; bp = *buffer; remain = *lenremain; @@ -640,6 +473,10 @@ kg_ctx_internalize(kcontext, argp, buffer, lenremain) ctx->established = (int) ibuf; (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); ctx->big_endian = (int) ibuf; + (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); + ctx->gsskrb5_version = (int) ibuf; + (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); + ctx->nctypes = (int) ibuf; if ((kret = kg_oid_internalize(kcontext, &ctx->mech_used, &bp, &remain))) { @@ -670,29 +507,21 @@ kg_ctx_internalize(kcontext, argp, buffer, lenremain) if (kret == EINVAL) kret = 0; } - if (!kret) { - if ((kret = kg_enc_desc_internalize(kcontext, - (krb5_pointer *) &edp, - &bp, &remain))) { - if (kret == EINVAL) - kret = 0; - } - else { - memcpy(&ctx->enc, edp, sizeof(ctx->enc)); - xfree(edp); - } + if (!kret && + (kret = krb5_internalize_opaque(kcontext, + KV5M_KEYBLOCK, + (krb5_pointer *) &ctx->enc, + &bp, &remain))) { + if (kret == EINVAL) + kret = 0; } - if (!kret) { - if ((kret = kg_enc_desc_internalize(kcontext, - (krb5_pointer *) &edp, - &bp, &remain))) { - if (kret == EINVAL) - kret = 0; - } - else { - memcpy(&ctx->seq, edp, sizeof(ctx->seq)); - xfree(edp); - } + if (!kret && + (kret = krb5_internalize_opaque(kcontext, + KV5M_KEYBLOCK, + (krb5_pointer *) &ctx->seq, + &bp, &remain))) { + if (kret == EINVAL) + kret = 0; } if (!kret) { @@ -708,6 +537,22 @@ kg_ctx_internalize(kcontext, argp, buffer, lenremain) (krb5_pointer *) &ctx->auth_context, &bp, &remain); + if (!kret) { + if (ctx->nctypes) { + if ((ctx->ctypes = (krb5_cksumtype *) + malloc(ctx->nctypes*sizeof(krb5_cksumtype))) == NULL){ + kret = ENOMEM; + } + + for (i=0; i<ctx->nctypes; i++) { + if (!kret) { + kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain); + ctx->ctypes[i] = (krb5_cksumtype) ibuf; + } + } + } + } + /* Get trailer */ if (!kret && !(kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)) && @@ -719,18 +564,10 @@ kg_ctx_internalize(kcontext, argp, buffer, lenremain) else { if (!kret && (ibuf != KG_CONTEXT)) kret = EINVAL; - if (ctx->seq.eblock.key) - krb5_free_keyblock(kcontext, ctx->seq.eblock.key); - if (ctx->seq.eblock.priv && ctx->seq.eblock.priv_size) - krb5_xfree(ctx->seq.eblock.priv); - if (ctx->seq.key) - krb5_free_keyblock(kcontext, ctx->seq.key); - if (ctx->enc.eblock.key) - krb5_free_keyblock(kcontext, ctx->enc.eblock.key); - if (ctx->enc.eblock.priv && ctx->enc.eblock.priv_size) - krb5_xfree(ctx->enc.eblock.priv); - if (ctx->enc.key) - krb5_free_keyblock(kcontext, ctx->enc.key); + if (ctx->seq) + krb5_free_keyblock(kcontext, ctx->seq); + if (ctx->enc) + krb5_free_keyblock(kcontext, ctx->enc); if (ctx->subkey) krb5_free_keyblock(kcontext, ctx->subkey); if (ctx->there) diff --git a/src/lib/gssapi/krb5/util_cksum.c b/src/lib/gssapi/krb5/util_cksum.c index 68561f10b..10e6b657f 100644 --- a/src/lib/gssapi/krb5/util_cksum.c +++ b/src/lib/gssapi/krb5/util_cksum.c @@ -36,20 +36,25 @@ kg_checksum_channel_bindings(context, cb, cksum, bigend) { int len; char *buf, *ptr; + size_t sumlen; + krb5_data plaind; krb5_error_code code; - /* initialize the the cksum and allocate the contents buffer */ + /* initialize the the cksum */ + if (code = krb5_c_checksum_length(context, CKSUMTYPE_RSA_MD5, &sumlen)) + return(code); + cksum->checksum_type = CKSUMTYPE_RSA_MD5; - cksum->length = krb5_checksum_size(context, CKSUMTYPE_RSA_MD5); - if ((cksum->contents = (krb5_octet *) xmalloc(cksum->length)) == NULL) { - return(ENOMEM); - } + cksum->length = sumlen; /* generate a buffer full of zeros if no cb specified */ if (cb == GSS_C_NO_CHANNEL_BINDINGS) { - memset(cksum->contents, '\0', cksum->length); - return(0); + if ((cksum->contents = (krb5_octet *) xmalloc(cksum->length)) == NULL) { + return(ENOMEM); + } + memset(cksum->contents, '\0', cksum->length); + return(0); } /* create the buffer to checksum into */ @@ -75,9 +80,11 @@ kg_checksum_channel_bindings(context, cb, cksum, bigend) /* checksum the data */ - if (code = krb5_calculate_checksum(context, CKSUMTYPE_RSA_MD5, - buf, len, NULL, 0, cksum)) { - xfree(cksum->contents); + plaind.length = len; + plaind.data = buf; + + if (code = krb5_c_make_checksum(context, CKSUMTYPE_RSA_MD5, 0, 0, + &plaind, cksum)) { xfree(buf); return(code); } diff --git a/src/lib/gssapi/krb5/util_crypt.c b/src/lib/gssapi/krb5/util_crypt.c index 1684377ad..93d46946c 100644 --- a/src/lib/gssapi/krb5/util_crypt.c +++ b/src/lib/gssapi/krb5/util_crypt.c @@ -20,6 +20,32 @@ * PERFORMANCE OF THIS SOFTWARE. */ +/* + * Copyright (C) 1998 by the FundsXpress, INC. + * + * All rights reserved. + * + * Export of this software from the United States of America may require + * a specific license from the United States Government. It is the + * responsibility of any person or organization contemplating export to + * obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of FundsXpress. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. FundsXpress makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + #include "k5-int.h" #include "gssapiP_krb5.h" #include <memory.h> @@ -31,103 +57,126 @@ static unsigned char zeros[8] = {0,0,0,0,0,0,0,0}; int -kg_confounder_size(ed) - krb5_gss_enc_desc *ed; +kg_confounder_size(context, key) + krb5_context context; + krb5_keyblock *key; { - /* XXX Abstraction violation!!! */ + krb5_error_code code; + size_t blocksize; + + if (code = krb5_c_block_size(context, key->enctype, &blocksize)) + return(-1); /* XXX */ - return(ed->eblock.crypto_entry->block_length); + return(blocksize); } krb5_error_code -kg_make_confounder(ed, buf) - krb5_gss_enc_desc *ed; +kg_make_confounder(context, key, buf) + krb5_context context; + krb5_keyblock *key; unsigned char *buf; { - /* XXX Abstraction violation!!! */ + krb5_error_code code; + size_t blocksize; + krb5_data random; + + if (code = krb5_c_block_size(context, key->enctype, &blocksize)) + return(code); - return(krb5_random_confounder(ed->eblock.crypto_entry->block_length, buf)); + random.length = blocksize; + random.data = buf; + + return(krb5_c_random_make_octets(context, &random)); } int -kg_encrypt_size(ed, n) - krb5_gss_enc_desc *ed; +kg_encrypt_size(context, key, n) + krb5_context context; + krb5_keyblock *key; int n; { - return(krb5_encrypt_size(n, ed->eblock.crypto_entry)); + krb5_error_code code; + size_t enclen; + + if (code = krb5_c_encrypt_length(context, key->enctype, n, &enclen)) + return(-1); /* XXX */ + + return(enclen); } krb5_error_code -kg_encrypt(context, ed, iv, in, out, length) +kg_encrypt(context, key, iv, in, out, length) krb5_context context; - krb5_gss_enc_desc *ed; + krb5_keyblock *key; krb5_pointer iv; krb5_pointer in; krb5_pointer out; int length; { krb5_error_code code; - krb5_pointer tmp; - - if (! ed->processed) { - if (code = krb5_process_key(context, &ed->eblock, ed->key)) - return(code); - ed->processed = 1; + size_t blocksize; + krb5_data ivd, *pivd, inputd; + krb5_enc_data outputd; + + if (iv) { + if (code = krb5_c_block_size(context, key->enctype, &blocksize)) + return(code); + + ivd.length = blocksize; + ivd.data = iv; + pivd = &ivd; + } else { + pivd = NULL; } - /* this is lame. the krb5 encryption interfaces no longer allow - you to encrypt in place. perhaps this should be fixed, but - dealing here is easier for now --marc */ - - if ((tmp = (krb5_pointer) xmalloc(length)) == NULL) - return(ENOMEM); + inputd.length = length; + inputd.data = in; - memcpy(tmp, in, length); + outputd.ciphertext.length = length; + outputd.ciphertext.data = out; - code = krb5_encrypt(context, tmp, out, length, &ed->eblock, - iv?iv:(krb5_pointer)zeros); - - xfree(tmp); - - if (code) - return(code); - - return(0); + return(krb5_c_encrypt(context, key, + /* XXX this routine is only used for the old + bare-des stuff which doesn't use the + key usage */ 0, pivd, &inputd, &outputd)); } /* length is the length of the cleartext. */ krb5_error_code -kg_decrypt(context, ed, iv, in, out, length) +kg_decrypt(context, key, iv, in, out, length) krb5_context context; - krb5_gss_enc_desc *ed; + krb5_keyblock *key; krb5_pointer iv; krb5_pointer in; krb5_pointer out; int length; { krb5_error_code code; - int elen; - char *buf; - - if (! ed->processed) { - if (code = krb5_process_key(context, &ed->eblock, ed->key)) - return(code); - ed->processed = 1; + size_t blocksize, enclen; + krb5_data ivd, *pivd, outputd; + krb5_enc_data inputd; + + if (iv) { + if (code = krb5_c_block_size(context, key->enctype, &blocksize)) + return(code); + + ivd.length = blocksize; + ivd.data = iv; + pivd = &ivd; + } else { + pivd = NULL; } - elen = krb5_encrypt_size(length, ed->eblock.crypto_entry); - if ((buf = (char *) xmalloc(elen)) == NULL) - return(ENOMEM); - - if (code = krb5_decrypt(context, in, buf, elen, &ed->eblock, - iv?iv:(krb5_pointer)zeros)) { - xfree(buf); - return(code); - } + inputd.enctype = ENCTYPE_UNKNOWN; + inputd.ciphertext.length = length; + inputd.ciphertext.data = in; - memcpy(out, buf, length); - xfree(buf); + outputd.length = length; + outputd.data = out; - return(0); + return(krb5_c_decrypt(context, key, + /* XXX this routine is only used for the old + bare-des stuff which doesn't use the + key usage */ 0, pivd, &inputd, &outputd)); } diff --git a/src/lib/gssapi/krb5/util_ctxsetup.c b/src/lib/gssapi/krb5/util_ctxsetup.c new file mode 100644 index 000000000..0add6bf73 --- /dev/null +++ b/src/lib/gssapi/krb5/util_ctxsetup.c @@ -0,0 +1,208 @@ +/* + * Copyright (C) 1998 by the FundsXpress, INC. + * + * All rights reserved. + * + * Export of this software from the United States of America may require + * a specific license from the United States Government. It is the + * responsibility of any person or organization contemplating export to + * obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of FundsXpress. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. FundsXpress makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "gssapiP_krb5.h" + +/* from the token, flags is stored directly. nctypes/ctypes is + allocated and returns the length and list of ctypes in the token. + noptions/options lists all the options which the caller cares + about. Those which are present in the token are filled in; the + order and length are not changed. If an error is returned, the + option list is in an indeterminate state. */ + +OM_uint32 +kg2_parse_token(minor_status, ptr, token_length, flags, nctypes, ctypes, + noptions, options, kmsg, mic) + OM_uint32 *minor_status; + unsigned char *ptr; + int token_length; + krb5_ui_4 *flags; + int *nctypes; /* OUT */ + krb5_cksumtype **ctypes; /* OUT */ + int noptions; + struct kg2_option *options; /* INOUT */ + krb5_data *kmsg; + krb5_data *mic; +{ + int field_length, i; + int opt_id; + + *ctypes = 0; + + /* read the flags */ + + if (token_length < 4) + goto defective; + *flags = (ptr[0]<<24) | (ptr[1]<<16) | (ptr[2]<<8) | ptr[3]; + ptr += 4; + token_length -= 4; + + /* read out the token list */ + + if (token_length < 2) + goto defective; + field_length = (ptr[0]<<8) | ptr[1]; + ptr += 2; + token_length -= 2; + + *nctypes = field_length; + + if (*nctypes == 0) { + *minor_status = 0; + return(GSS_S_DEFECTIVE_TOKEN); + } + + if ((*ctypes = (krb5_cksumtype *) + malloc((*nctypes) * sizeof(krb5_cksumtype))) == NULL) { + *minor_status = ENOMEM; + return(GSS_S_FAILURE); + } + + for (i=0; i<field_length; i++) { + if (token_length < 4) + goto defective; + + (*ctypes)[i] = (krb5_cksumtype) ((ptr[0]<<24) | (ptr[1]<<16) | + (ptr[2]<<8) | ptr[3]); + ptr += 4; + token_length -= 4; + } + + do { + if (token_length < 4) + goto defective; + opt_id = (ptr[0]<<8) | ptr[1]; + field_length = (ptr[2]<<8) | ptr[3]; + ptr += 4; + token_length -= 4; + + if (token_length < field_length) + goto defective; + + for (i=0; i<noptions; i++) { + if (options[i].option_id = opt_id) { + options[i].length = field_length; + options[i].data = ptr; + } + break; + } + + ptr += field_length; + token_length -= field_length; + } while (opt_id); + + if (token_length < 2) + goto defective; + field_length = (ptr[0]<<8) | ptr[1]; + ptr += 2; + token_length -= 2; + + if (token_length < field_length) + goto defective; + + kmsg->length = field_length; + kmsg->data = ptr; + + ptr += field_length; + token_length -= field_length; + + /* if there's anything left, assume it's a mic. the mic isn't + necessarily present */ + + if (mic && token_length) { + if (token_length < 2) + goto defective; + field_length = (ptr[0]<<8) | ptr[1]; + ptr += 2; + token_length -= 2; + + if (token_length < field_length) + goto defective; + + mic->length = field_length; + mic->data = ptr; + + ptr += field_length; + token_length -= field_length; + } else if (mic) { + mic->length = 0; + mic->data = ptr; + } + + if (token_length) + goto defective; + + return(GSS_S_COMPLETE); + +defective: + if (*ctypes) + free(*ctypes); + + *minor_status = 0; + return(GSS_S_DEFECTIVE_TOKEN); +} + +/* nc1/c1 will be modified to contain the intersection of the + two lists. */ + +void +kg2_intersect_ctypes(nc1, c1, nc2, c2) + int *nc1; + krb5_cksumtype *c1; + int nc2; + const krb5_cksumtype *c2; +{ + int i, j, count; + krb5_cksumtype tmp; + + count = 0; + + for (i=0; i<*nc1; i++) { + /* first, check to make sure that c1[i] isn't a duplicate in c1 */ + for (j=0; j<i; j++) + if (c1[i] == c1[j]) + break; + if (j<i) + continue; + /* check if c1[i] is in c2. If it is, keep it by swapping + it into c1[count] and incrementing count. If count < i, then + that field has already been looked at and skipped as + not intersecting, which is ok. */ + + for (j=0; j<nc2; j++) + if (c1[i] == c2[j]) + break; + if ((j<nc2) && (count != i)) { + tmp = c1[count]; + c1[count] = c1[i]; + c1[i] = tmp; + } + count++; + } + + *nc1 = count; +} + diff --git a/src/lib/gssapi/krb5/util_seed.c b/src/lib/gssapi/krb5/util_seed.c index 14f365245..206ee68a7 100644 --- a/src/lib/gssapi/krb5/util_seed.c +++ b/src/lib/gssapi/krb5/util_seed.c @@ -36,24 +36,20 @@ kg_make_seed(context, key, seed) unsigned char *seed; { krb5_error_code code; - krb5_gss_enc_desc ed; + krb5_keyblock *tmpkey; int i; - if (code = krb5_copy_keyblock(context, key, &ed.key)) + if (code = krb5_copy_keyblock(context, key, &tmpkey)) return(code); /* reverse the key bytes, as per spec */ - for (i=0; i<ed.key->length; i++) - ed.key->contents[i] = key->contents[key->length - 1 - i]; + for (i=0; i<tmpkey->length; i++) + tmpkey->contents[i] = key->contents[key->length - 1 - i]; - krb5_use_enctype(context, &ed.eblock, ENCTYPE_DES_CBC_RAW); - ed.processed = 0; + code = kg_encrypt(context, tmpkey, NULL, zeros, seed, 16); - code = kg_encrypt(context, &ed, NULL, zeros, seed, 16); - - krb5_finish_key(context, &ed.eblock); - krb5_free_keyblock(context, ed.key); + krb5_free_keyblock(context, tmpkey); return(code); } diff --git a/src/lib/gssapi/krb5/util_seqnum.c b/src/lib/gssapi/krb5/util_seqnum.c index ed9293f77..e14b2f3fe 100644 --- a/src/lib/gssapi/krb5/util_seqnum.c +++ b/src/lib/gssapi/krb5/util_seqnum.c @@ -27,9 +27,9 @@ */ krb5_error_code -kg_make_seq_num(context, ed, direction, seqnum, cksum, buf) +kg_make_seq_num(context, key, direction, seqnum, cksum, buf) krb5_context context; - krb5_gss_enc_desc *ed; + krb5_keyblock *key; int direction; krb5_int32 seqnum; unsigned char *cksum; @@ -47,12 +47,12 @@ kg_make_seq_num(context, ed, direction, seqnum, cksum, buf) plain[6] = direction; plain[7] = direction; - return(kg_encrypt(context, ed, cksum, plain, buf, 8)); + return(kg_encrypt(context, key, cksum, plain, buf, 8)); } -krb5_error_code kg_get_seq_num(context, ed, cksum, buf, direction, seqnum) +krb5_error_code kg_get_seq_num(context, key, cksum, buf, direction, seqnum) krb5_context context; - krb5_gss_enc_desc *ed; + krb5_keyblock *key; unsigned char *cksum; unsigned char *buf; int *direction; @@ -61,7 +61,7 @@ krb5_error_code kg_get_seq_num(context, ed, cksum, buf, direction, seqnum) krb5_error_code code; unsigned char plain[8]; - if (code = kg_decrypt(context, ed, cksum, buf, plain, 8)) + if (code = kg_decrypt(context, key, cksum, buf, plain, 8)) return(code); if ((plain[4] != plain[5]) || diff --git a/src/lib/gssapi/krb5/wrap_size_limit.c b/src/lib/gssapi/krb5/wrap_size_limit.c index f2366d16e..745949260 100644 --- a/src/lib/gssapi/krb5/wrap_size_limit.c +++ b/src/lib/gssapi/krb5/wrap_size_limit.c @@ -20,6 +20,32 @@ * PERFORMANCE OF THIS SOFTWARE. */ +/* + * Copyright (C) 1998 by the FundsXpress, INC. + * + * All rights reserved. + * + * Export of this software from the United States of America may require + * a specific license from the United States Government. It is the + * responsibility of any person or organization contemplating export to + * obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of FundsXpress. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. FundsXpress makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + #include "gssapiP_krb5.h" /* @@ -39,8 +65,7 @@ krb5_gss_wrap_size_limit(minor_status, context_handle, conf_req_flag, { krb5_context context; krb5_gss_ctx_id_rec *ctx; - OM_uint32 cfsize; - OM_uint32 ohlen; + krb5_error_code code; if (GSS_ERROR(kg_get_context(minor_status, &context))) return(GSS_S_FAILURE); @@ -63,19 +88,86 @@ krb5_gss_wrap_size_limit(minor_status, context_handle, conf_req_flag, return(GSS_S_NO_CONTEXT); } - /* Calculate the token size and subtract that from the output size */ - cfsize = (conf_req_flag) ? kg_confounder_size(&ctx->enc) : 0; - ohlen = g_token_size((gss_OID) ctx->mech_used, - (unsigned int) cfsize + ctx->cksum_size + 14); + if (ctx->gsskrb5_version == 2000) { + if (conf_req_flag) { + /* this is pretty gross. take the max output, and call + krb5_c_encrypt_length to see how much overhead is added + on. subtract that much, and see if it fits in the + requested space. If not, start subtracting 1 until it + does. This doesn't necessarily give us the optimal + packing, but I think that's ok (I could start adding 1 + until I went over, but that seems like it's not worth + the effort). This is probably O(blocksize), but that's + never going to be large. */ + + OM_uint32 headerlen, plainlen; + size_t enclen; + + headerlen = g_token_size((gss_OID) ctx->mech_used, 2); + plainlen = req_output_size - headerlen; + + if (code = krb5_c_encrypt_length(context, ctx->enc->enctype, + plainlen, &enclen)) { + *minor_status = code; + return(GSS_S_FAILURE); + } + + plainlen -= plainlen - (enclen - plainlen); + + if (code = krb5_c_encrypt_length(context, ctx->enc->enctype, + plainlen, &enclen)) { + *minor_status = code; + return(GSS_S_FAILURE); + } - if (ohlen < req_output_size) + while (headerlen + enclen > req_output_size) { + plainlen--; + + if (code = krb5_c_encrypt_length(context, ctx->enc->enctype, + plainlen, &enclen)) { + *minor_status = code; + return(GSS_S_FAILURE); + } + } + + /* subtract off the fixed size inside the encrypted part */ + + plainlen -= 7; + + *max_input_size = plainlen; + } else { + size_t cksumlen; + OM_uint32 headerlen; + + if (code = krb5_c_checksum_length(context, ctx->ctypes[0], + &cksumlen)) { + *minor_status = code; + return(GSS_S_FAILURE); + } + + headerlen = g_token_size((gss_OID) ctx->mech_used, 13 + cksumlen); + + *max_input_size = req_output_size - headerlen; + } + } else { + OM_uint32 cfsize; + OM_uint32 ohlen; + + /* Calculate the token size and subtract that from the output size */ + cfsize = (conf_req_flag) ? kg_confounder_size(context, ctx->enc) : 0; + ohlen = g_token_size((gss_OID) ctx->mech_used, + (unsigned int) cfsize + ctx->cksum_size + 14); + + if (ohlen < req_output_size) /* * Cannot have trailer length that will cause us to pad over * our length */ *max_input_size = (req_output_size - ohlen - 1) & (~7); - else + else *max_input_size = 0; + } + *minor_status = 0; return(GSS_S_COMPLETE); } |
