/* Make this a function eventually? */
#define krb5int_zap_data(ptr, len) memset((volatile void *)ptr, 0, len)
+#if defined(__GNUC__) && defined(__GLIBC__)
+/* GNU libc generates multiple bogus initialization warnings if we
+ pass memset a volatile pointer. The compiler should do well enough
+ with memset even without GNU libc's attempt at optimization. */
+#undef memset
+#endif
#define zap(p,l) krb5int_zap_data(p,l)
/* A definition of init_state for DES based encryption systems.
code_string = "KADM5_AUTH_INSUFFICIENT"; break;
case KADM5_BAD_DB: code_string = "KADM5_BAD_DB"; break;
case KADM5_DUP: code_string = "KADM5_DUP"; break;
- case KADM5_RPC_ERROR: code_string = "KADM5_RPC_ERROR"; break;
+ case /*KADM5_RPC_ERROR*/ (43787528L): code_string = "KADM5_RPC_ERROR"; break;
case KADM5_NO_SRV: code_string = "KADM5_NO_SRV"; break;
case KADM5_BAD_HIST_KEY:
code_string = "KADM5_BAD_HIST_KEY"; break;
code_string = "OVSEC_KADM_AUTH_INSUFFICIENT"; break;
case OVSEC_KADM_BAD_DB: code_string = "OVSEC_KADM_BAD_DB"; break;
case OVSEC_KADM_DUP: code_string = "OVSEC_KADM_DUP"; break;
- case OVSEC_KADM_RPC_ERROR: code_string = "OVSEC_KADM_RPC_ERROR"; break;
+ case /*OVSEC_KADM_RPC_ERROR*/(43787528L): code_string = "OVSEC_KADM_RPC_ERROR"; break;
case OVSEC_KADM_NO_SRV: code_string = "OVSEC_KADM_NO_SRV"; break;
case OVSEC_KADM_BAD_HIST_KEY:
code_string = "OVSEC_KADM_BAD_HIST_KEY"; break;
/* XXXX This is a necessary evil until the spec is fixed */
#define GSS_S_CRED_UNAVAIL GSS_S_FAILURE
+extern void _log(const char *, ...);
+extern void _log_block(const char *, int, const char *, void *, size_t);
+#define _log_block2(LABEL,PTR,SIZE) _log_block(__FILE__,__LINE__,LABEL,PTR,SIZE)
+#define SFILE (strrchr(__FILE__,'/') ? 1+strrchr(__FILE__,'/') : __FILE__)
+#undef GSS_S_DEFECTIVE_TOKEN
+#define GSS_S_DEFECTIVE_TOKEN (defective(SFILE,__LINE__),(((OM_uint32) 9ul) << GSS_C_ROUTINE_ERROR_OFFSET))
+
#endif /* _GSSAPI_H_ */
unsigned char **buf, int tok_type);
gss_int32 g_verify_token_header (gss_OID mech, unsigned int *body_size,
- unsigned char **buf, int tok_type,
- unsigned int toksize_in);
+ unsigned char **buf, int tok_type,
+ unsigned int toksize_in,
+ int wrapper_required);
OM_uint32 g_display_major_status (OM_uint32 *minor_status,
OM_uint32 status_value,
*vqueue = q;
return 0;
}
+
+/* debugging */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <time.h>
+#if defined( __linux__)
+/*# define LOGPATH "/dev/pts/7"*/
+#define LOGPATH "/tmp/gsslog"
+#elif defined(__MACH__)
+# define LOGPATH "/dev/ttyp6" /* laptop */
+#endif
+void _log(const char *fmt, ...) {
+#if 1
+ static FILE *logf;
+ va_list x;
+ if (logf == 0) {
+ logf = fopen(LOGPATH, "a");
+ if (logf)
+ setvbuf(logf, 0, _IONBF, 0);
+ }
+ if (logf == 0)
+ return;
+ va_start(x, fmt);
+#if 0
+ fprintf(logf,"[%d]", getpid());
+#else
+ {
+ struct timeval tv;
+ struct tm tm;
+ time_t tvsec;
+ char buf[40];
+ char *p;
+
+ sprintf(buf,"[%d", getpid());
+ p = buf + strlen(buf);
+ gettimeofday(&tv, 0) == 0
+ && (tvsec = tv.tv_sec)
+ && strftime(p, buf + sizeof(buf) - p,
+ ":%F-%T", localtime_r(&tvsec, &tm)) > 0
+ && (p += strlen(p))
+ && (buf + sizeof(buf) - p >= 10)
+ && sprintf(p, ".%06ld", (long) tv.tv_usec);
+ strcat(buf, "]");
+ fprintf(logf, "%s", buf);
+ }
+#endif
+ vfprintf(logf, fmt, x);
+ va_end(x);
+#endif
+}
+
+int defective(const char *f,int l) {
+ _log("%s:%d: reporting defective token\n", f, l);
+ return -1;
+}
* mechanism in the token does not match the mech argument. buf and
* *body_size are left unmodified on error.
*/
-gss_int32 g_verify_token_header(mech, body_size, buf_in, tok_type, toksize_in)
+static gss_int32 g_bad_tok_header = G_BAD_TOK_HEADER;
+#undef G_BAD_TOK_HEADER
+#define G_BAD_TOK_HEADER (_log("%s:%d: returning G_BAD_TOK_HEADER", SFILE, __LINE__), g_bad_tok_header)
+gss_int32 g_verify_token_header(mech, body_size, buf_in, tok_type, toksize_in,
+ wrapper_required)
gss_OID mech;
unsigned int *body_size;
unsigned char **buf_in;
int tok_type;
unsigned int toksize_in;
+ int wrapper_required;
{
unsigned char *buf = *buf_in;
int seqsize;
gss_OID_desc toid;
int toksize = toksize_in;
+#define SFILE (strrchr(__FILE__,'/') ? 1+strrchr(__FILE__,'/') : __FILE__)
+ _log("%s:%d: %s(tok_type=0x%x, toksize=%d, wrapper_required=%d)\n",
+ SFILE, __LINE__, __func__, tok_type, toksize, wrapper_required);
+ _log_block2("input token", buf, toksize);
+
+#define LOG() _log("%s:%d: here\n", SFILE, __LINE__)
if ((toksize-=1) < 0)
return(G_BAD_TOK_HEADER);
- if (*buf++ != 0x60)
- return(G_BAD_TOK_HEADER);
+ if (*buf++ != 0x60) {
+ if (wrapper_required)
+ return(G_BAD_TOK_HEADER);
+ buf--;
+ toksize++;
+ goto skip_wrapper;
+ }
if ((seqsize = der_read_length(&buf, &toksize)) < 0)
return(G_BAD_TOK_HEADER);
if (! g_OID_equal(&toid, mech))
return G_WRONG_MECH;
+skip_wrapper:
if (tok_type != -1) {
+ _log("%s:%d: toksize=%d\n", SFILE, __LINE__, toksize);
if ((toksize-=2) < 0)
return(G_BAD_TOK_HEADER);
+ _log("%s:%d: buf@%p: %02x %02x\n", SFILE, __LINE__,
+ buf, buf[0], buf[1]);
if ((*buf++ != ((tok_type>>8)&0xff)) ||
- (*buf++ != (tok_type&0xff)))
+ (*buf++ != (tok_type&0xff))) {
+ _log("%s:%d: G_WRONG_TOKID\n", SFILE, __LINE__);
return(G_WRONG_TOKID);
+ }
}
- *buf_in = buf;
- *body_size = toksize;
+ *buf_in = buf;
+ *body_size = toksize;
- return 0;
- }
+ return 0;
+}
+2003-09-25 Ken Raeburn <raeburn@mit.edu>
+
+ * gssapiP_krb5.h (struct _krb5_gss_ctx_id_rec): Deleted fields
+ ctypes and nctypes.
+ * delete_sec_context.c, init_sec_context.c, ser_sctx.c: Removed
+ references.
+
2003-07-19 Ezra Peisach <epeisach@mit.edu>
* acquire_cred.c (krb5_gss_register_acceptor_identity): Allocate
$(srcdir)/inq_cred.c \
$(srcdir)/inq_names.c \
$(srcdir)/k5seal.c \
+ $(srcdir)/k5sealv3.c \
$(srcdir)/k5unseal.c \
$(srcdir)/krb5_gss_glue.c \
$(srcdir)/process_context_token.c \
$(OUTPRE)inq_cred.$(OBJEXT) \
$(OUTPRE)inq_names.$(OBJEXT) \
$(OUTPRE)k5seal.$(OBJEXT) \
+ $(OUTPRE)k5sealv3.$(OBJEXT) \
$(OUTPRE)k5unseal.$(OBJEXT) \
$(OUTPRE)krb5_gss_glue.$(OBJEXT) \
$(OUTPRE)process_context_token.$(OBJEXT) \
inq_cred.o \
inq_names.o \
k5seal.o \
+ k5sealv3.o \
k5unseal.o \
krb5_gss_glue.o \
process_context_token.o \
ptr = (unsigned char *) input_token->value;
+ _log("%s:%d: here\n", SFILE, __LINE__);
if (!(code = g_verify_token_header((gss_OID) gss_mech_krb5,
&(ap_req.length),
&ptr, KG_TOK_CTX_AP_REQ,
- input_token->length))) {
+ input_token->length, 1))) {
mech_used = gss_mech_krb5;
} 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))) {
+ input_token->length, 1))) {
/*
* Previous versions of this library used the old mech_id
* and some broken behavior (wrong IV on checksum
major_status = GSS_S_DEFECTIVE_TOKEN;
goto fail;
}
+ _log("%s:%d: here\n", SFILE, __LINE__);
sptr = (char *) ptr;
TREAD_STR(sptr, ap_req.data, ap_req.length);
goto fail;
}
+ ctx->proto = 0;
switch(ctx->subkey->enctype) {
case ENCTYPE_DES_CBC_MD5:
case ENCTYPE_DES_CBC_CRC:
/*SUPPRESS 113*/
ctx->enc->contents[i] ^= 0xf0;
- if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->seq))) {
- major_status = GSS_S_FAILURE;
- goto fail;
- }
-
- break;
+ goto copy_subkey_to_seq;
case ENCTYPE_DES3_CBC_SHA1:
ctx->subkey->enctype = ENCTYPE_DES3_CBC_RAW;
ctx->sealalg = SEAL_ALG_DES3KD;
/* fill in the encryption descriptors */
-
+ copy_subkey:
if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc))) {
major_status = GSS_S_FAILURE;
goto fail;
}
-
+ copy_subkey_to_seq:
if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->seq))) {
major_status = GSS_S_FAILURE;
goto fail;
}
-
break;
- case ENCTYPE_ARCFOUR_HMAC:
- ctx->signalg = SGN_ALG_HMAC_MD5 ;
- ctx->cksum_size = 8;
- ctx->sealalg = SEAL_ALG_MICROSOFT_RC4 ;
-
- code = krb5_copy_keyblock (context, ctx->subkey, &ctx->enc);
- if (code)
- goto fail;
- code = krb5_copy_keyblock (context, ctx->subkey, &ctx->seq);
- if (code) {
- krb5_free_keyblock (context, ctx->enc);
- goto fail;
- }
- break;
+
+ case ENCTYPE_ARCFOUR_HMAC:
+ ctx->signalg = SGN_ALG_HMAC_MD5 ;
+ ctx->cksum_size = 8;
+ ctx->sealalg = SEAL_ALG_MICROSOFT_RC4 ;
+ goto copy_subkey;
default:
- code = KRB5_BAD_ENCTYPE;
- goto fail;
+ ctx->signalg = -1;
+ ctx->sealalg = -1;
+ ctx->proto = 1;
+ code = krb5int_c_mandatory_cksumtype(context, ctx->subkey->enctype,
+ &ctx->cksumtype);
+ if (code)
+ goto fail;
+ code = krb5_c_checksum_length(context, ctx->cksumtype,
+ &ctx->cksum_size);
+ if (code)
+ goto fail;
+ ctx->have_acceptor_subkey = 0;
+ goto copy_subkey;
}
ctx->endtime = ticket->enc_part2->times.endtime;
krb5_free_ticket(context, ticket); /* Done with ticket */
- krb5_auth_con_getremoteseqnumber(context, auth_context, &ctx->seq_recv);
+ {
+ krb5_ui_4 seq_temp;
+ krb5_auth_con_getremoteseqnumber(context, auth_context, &seq_temp);
+ ctx->seq_recv = seq_temp;
+ }
if ((code = krb5_timeofday(context, &now))) {
major_status = GSS_S_FAILURE;
g_order_init(&(ctx->seqstate), ctx->seq_recv,
(ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0,
- (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0);
+ (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0, ctx->proto);
/* at this point, the entire context structure is filled in,
so it can be released. */
if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) {
unsigned char * ptr3;
+ krb5_ui_4 seq_temp;
+
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);
+ krb5_auth_con_getlocalseqnumber(context, auth_context, &seq_temp);
+ ctx->seq_send = seq_temp & 0xffffffffL;
/* the reply token hasn't been sent yet, but that's ok. */
ctx->gss_flags |= GSS_C_PROT_READY_FLAG;
return(GSS_S_CRED_UNAVAIL);
}
+ _log("%s:%d: krb5_gss_keytab=%s ops=%p\n", SFILE, __LINE__,
+ krb5_gss_keytab ? krb5_gss_keytab : "(null)", kt->ops);
+
if (desired_name != GSS_C_NO_NAME) {
princ = (krb5_principal) desired_name;
if ((code = krb5_kt_get_entry(context, kt, princ, 0, 0, &entry))) {
+ {
+ char *p, ktname[BUFSIZ];
+ krb5_error_code err;
+ if (krb5_unparse_name(context, princ, &p))
+ p = NULL;
+ if (err = krb5_kt_get_name(context, kt, ktname, sizeof(ktname)))
+ sprintf(ktname, "(error %d/%s)", err, error_message(err));
+ _log("%s:%d: error %d/%s; desired_name=%s\n", SFILE, __LINE__,
+ code, error_message(code),
+ p ? p : "(error)");
+ free(p);
+ }
(void) krb5_kt_close(context, kt);
if (code == KRB5_KT_NOTFOUND)
*minor_status = KG_KEYTAB_NOMATCH;
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);
SEAL_ALG_DES3KD = 0x0002
};
+/* for 3DES */
#define KG_USAGE_SEAL 22
#define KG_USAGE_SIGN 23
#define KG_USAGE_SEQ 24
+/* for draft-ietf-krb-wg-gssapi-cfx-01 */
+#define KG_USAGE_ACCEPTOR_SEAL 22
+#define KG_USAGE_ACCEPTOR_SIGN 23
+#define KG_USAGE_INITIATOR_SEAL 24
+#define KG_USAGE_INITIATOR_SIGN 25
+
enum qop {
GSS_KRB5_INTEG_C_QOP_MD5 = 0x0001, /* *partial* MD5 = "MD2.5" */
GSS_KRB5_INTEG_C_QOP_DES_MD5 = 0x0002,
krb5_timestamp tgt_expire;
} krb5_gss_cred_id_rec, *krb5_gss_cred_id_t;
+#define GSS_CFX_SKIPS_ASN1_WRAPPER 0
+
typedef struct _krb5_gss_ctx_id_rec {
- int initiate; /* nonzero if initiating, zero if accepting */
+ unsigned int initiate : 1; /* nonzero if initiating, zero if accepting */
+ unsigned int established : 1;
+ unsigned int big_endian : 1;
+ unsigned int have_acceptor_subkey : 1;
+ unsigned int seed_init : 1; /* XXX tested but never actually set */
OM_uint32 gss_flags;
- int seed_init;
unsigned char seed[16];
krb5_principal here;
krb5_principal there;
krb5_keyblock *subkey;
int signalg;
- int cksum_size;
+ size_t cksum_size;
int sealalg;
krb5_keyblock *enc;
krb5_keyblock *seq;
/* 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;
+ gssint_uint64 seq_send;
+ gssint_uint64 seq_recv;
void *seqstate;
- int established;
- int big_endian;
krb5_auth_context auth_context;
gss_OID_desc *mech_used;
- int nctypes;
- krb5_cksumtype *ctypes;
+ /* Protocol spec revision
+ 0 => RFC 1964 with 3DES and RC4 enhancements
+ 1 => draft-ietf-krb-wg-gssapi-cfx-01
+ No others defined so far. */
+ int proto;
+ krb5_cksumtype cksumtype;
} krb5_gss_ctx_id_rec, *krb5_gss_ctx_id_t;
extern void *kg_vdb;
(gss_OID oid
);
+krb5_error_code gss_krb5int_make_seal_token_v3(krb5_context,
+ krb5_gss_ctx_id_rec *,
+ const gss_buffer_desc *,
+ gss_buffer_t,
+ int, int);
+
#endif /* _GSSAPIP_KRB5_H_ */
int is_duplicate_enctype;
int is_wanted_enctype;
static const krb5_enctype wanted_enctypes[] = {
-#if 1
+ ENCTYPE_AES256_CTS_HMAC_SHA1_96, ENCTYPE_AES128_CTS_HMAC_SHA1_96,
ENCTYPE_DES3_CBC_SHA1,
-#endif
ENCTYPE_ARCFOUR_HMAC,
ENCTYPE_DES_CBC_CRC,
ENCTYPE_DES_CBC_MD5, ENCTYPE_DES_CBC_MD4,
krb5_error_code code;
int i;
+ ctx->have_acceptor_subkey = 0;
+ ctx->proto = 0;
+ ctx->cksumtype = 0;
switch(ctx->subkey->enctype) {
case ENCTYPE_DES_CBC_MD5:
case ENCTYPE_DES_CBC_MD4:
goto fail;
for (i=0; i<ctx->enc->length; i++)
- /*SUPPRESS 113*/
ctx->enc->contents[i] ^= 0xf0;
- if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->seq)))
- goto fail;
-
- break;
+ goto copy_subkey_to_seq;
case ENCTYPE_DES3_CBC_SHA1:
+ /* MIT extension */
ctx->subkey->enctype = ENCTYPE_DES3_CBC_RAW;
ctx->signalg = SGN_ALG_HMAC_SHA1_DES3_KD;
ctx->cksum_size = 20;
ctx->sealalg = SEAL_ALG_DES3KD;
+ copy_subkey:
code = krb5_copy_keyblock (context, ctx->subkey, &ctx->enc);
if (code)
goto fail;
+ copy_subkey_to_seq:
code = krb5_copy_keyblock (context, ctx->subkey, &ctx->seq);
if (code) {
krb5_free_keyblock (context, ctx->enc);
goto fail;
}
break;
+
case ENCTYPE_ARCFOUR_HMAC:
+ /* Microsoft extension */
ctx->signalg = SGN_ALG_HMAC_MD5 ;
ctx->cksum_size = 8;
ctx->sealalg = SEAL_ALG_MICROSOFT_RC4 ;
- code = krb5_copy_keyblock (context, ctx->subkey, &ctx->enc);
- if (code)
- goto fail;
- code = krb5_copy_keyblock (context, ctx->subkey, &ctx->seq);
- if (code) {
- krb5_free_keyblock (context, ctx->enc);
- goto fail;
- }
- break;
-#if 0
- case ENCTYPE_DES3_CBC_MD5:
- enctype = ENCTYPE_DES3_CBC_RAW;
- ctx->signalg = 3;
- ctx->cksum_size = 16;
- ctx->sealalg = 1;
- break;
-#endif
+ goto copy_subkey;
+
default:
- *minor_status = KRB5_BAD_ENCTYPE;
- return GSS_S_FAILURE;
+ /* Fill some fields we shouldn't be using on this path
+ with garbage. */
+ ctx->signalg = -10;
+ ctx->sealalg = -10;
+
+ ctx->proto = 1;
+ code = krb5int_c_mandatory_cksumtype(context, ctx->subkey->enctype,
+ &ctx->cksumtype);
+ if (code)
+ goto fail;
+ code = krb5_c_checksum_length(context, ctx->cksumtype,
+ &ctx->cksum_size);
+ if (code)
+ goto fail;
+ goto copy_subkey;
}
fail:
*minor_status = code;
ctx->seed_init = 0;
ctx->big_endian = 0; /* all initiators do little-endian, as per spec */
ctx->seqstate = 0;
- ctx->nctypes = 0;
- ctx->ctypes = 0;
if ((code = krb5_timeofday(context, &now)))
goto fail;
{
/* gsskrb5 v1 */
+ krb5_ui_4 seq_temp;
if ((code = make_ap_req_v1(context, ctx,
cred, k_cred, input_chan_bindings,
mech_type, &token))) {
goto fail;
}
- krb5_auth_con_getlocalseqnumber(context, ctx->auth_context,
- &ctx->seq_send);
+ krb5_auth_con_getlocalseqnumber(context, ctx->auth_context, &seq_temp);
+ ctx->seq_send = seq_temp;
krb5_auth_con_getsendsubkey(context, ctx->auth_context,
&ctx->subkey);
}
ctx->seq_recv = ctx->seq_send;
g_order_init(&(ctx->seqstate), ctx->seq_recv,
(ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0,
- (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0);
+ (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0, ctx->proto);
ctx->gss_flags |= GSS_C_PROT_READY_FLAG;
ctx->established = 1;
return(GSS_S_COMPLETE);
krb5_free_principal(context, ctx_free->there);
if (ctx_free->subkey)
krb5_free_keyblock(context, ctx_free->subkey);
- if (ctx_free->ctypes)
- krb5_free_cksumtypes(context, ctx_free->ctypes);
xfree(ctx_free);
} else
(void)krb5_gss_delete_sec_context(minor_status, context_handle, NULL);
ptr = (unsigned char *) input_token->value;
+ _log("%s:%d: here\n", SFILE, __LINE__);
if (g_verify_token_header((gss_OID) ctx->mech_used,
&(ap_rep.length),
&ptr, KG_TOK_CTX_AP_REP,
- input_token->length)) {
+ input_token->length, 1)) {
if (g_verify_token_header((gss_OID) ctx->mech_used,
&(ap_rep.length),
&ptr, KG_TOK_CTX_ERROR,
- input_token->length) == 0) {
+ input_token->length, 1) == 0) {
/* Handle a KRB_ERROR message from the server */
return(GSS_S_DEFECTIVE_TOKEN);
}
}
+ _log("%s:%d: here\n", SFILE, __LINE__);
sptr = (char *) ptr; /* PC compiler bug */
TREAD_STR(sptr, ap_rep.data, ap_rep.length);
ctx->seq_recv = ap_rep_data->seq_number;
g_order_init(&(ctx->seqstate), ctx->seq_recv,
(ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0,
- (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) !=0);
+ (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) !=0, ctx->proto);
+
+ if (ctx->proto == 1 && ap_rep_data->subkey) {
+ /* Keep acceptor's subkey. */
+ ctx->have_acceptor_subkey = 1;
+ code = krb5_copy_keyblock(context, ap_rep_data->subkey,
+ &ctx->subkey);
+ if (code)
+ goto fail;
+ }
/* free the ap_rep_data */
krb5_free_ap_rep_enc_part(context, ap_rep_data);
make_seal_token_v1 (krb5_context context,
krb5_keyblock *enc,
krb5_keyblock *seq,
- krb5_ui_4 *seqnum,
+ gssint_uint64 *seqnum,
int direction,
gss_buffer_t text,
gss_buffer_t token,
/* that's it. return the token */
(*seqnum)++;
+ *seqnum &= 0xffffffffL;
token->length = tlen;
token->value = (void *) t;
output_message_buffer->length = 0;
output_message_buffer->value = NULL;
- /* only default qop or matching established cryptosystem is allowed */
-
-#if 0
- switch (qop_req & GSS_KRB5_CONF_C_QOP_MASK) {
- case GSS_C_QOP_DEFAULT:
- break;
- default:
- unknown_qop:
- *minor_status = (OM_uint32) G_UNKNOWN_QOP;
- return GSS_S_FAILURE;
- case GSS_KRB5_CONF_C_QOP_DES:
- if (ctx->sealalg != SEAL_ALG_DES) {
- bad_qop:
- *minor_status = (OM_uint32) G_BAD_QOP;
- return GSS_S_FAILURE;
- }
- break;
- case GSS_KRB5_CONF_C_QOP_DES3:
- if (ctx->sealalg != SEAL_ALG_DES3)
- goto bad_qop;
- break;
- }
- switch (qop_req & GSS_KRB5_INTEG_C_QOP_MASK) {
- case GSS_C_QOP_DEFAULT:
- break;
- default:
- goto unknown_qop;
- case GSS_KRB5_INTEG_C_QOP_MD5:
- case GSS_KRB5_INTEG_C_QOP_DES_MD5:
- case GSS_KRB5_INTEG_C_QOP_DES_MAC:
- if (ctx->sealalg != SEAL_ALG_DES)
- goto bad_qop;
- break;
- case GSS_KRB5_INTEG_C_QOP_HMAC_SHA1:
- if (ctx->sealalg != SEAL_ALG_DES3KD)
- goto bad_qop;
- break;
- }
-#else
+ /* Only default qop or matching established cryptosystem is allowed.
+
+ There are NO EXTENSIONS to this set for AES and friends! The
+ new spec says "just use 0". The old spec plus extensions would
+ actually allow for certain non-zero values. Fix this to handle
+ them later. */
if (qop_req != 0) {
*minor_status = (OM_uint32) G_UNKNOWN_QOP;
return GSS_S_FAILURE;
}
-#endif
/* validate the context handle */
if (! kg_validate_ctx_id(context_handle)) {
return(GSS_S_FAILURE);
}
- 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);
+ switch (ctx->proto)
+ {
+ case 0:
+ 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);
+ break;
+ case 1:
+ code = gss_krb5int_make_seal_token_v3(context, ctx,
+ input_message_buffer,
+ output_message_buffer,
+ conf_req_flag, toktype);
+ break;
+ default:
+ code = G_UNKNOWN_QOP; /* XXX */
+ break;
+ }
if (code) {
*minor_status = code;
return 1;
}
+static const gss_buffer_desc empty_message = { 0, 0 };
+
+#define FLAG_SENDER_IS_ACCEPTOR 0x80
+#define FLAG_WRAP_CONFIDENTIAL 0x40
+#define FLAG_ACCEPTOR_SUBKEY 0x20
+
+void
+_log_block(const char *file, int line, const char *label,
+ void *vptr, size_t len)
+{
+ char b[8 * 4 + 4];
+ int i, j;
+ if (strrchr(file, '/'))
+ file = 1 + strrchr(file, '/');
+ _log("%s:%d: %s: %d at %p\n", file, line, label, len, vptr);
+ for (i = 0; i < (len + 7) / 8; i++) {
+ unsigned char *base = (i * 8) + (unsigned char *)vptr;
+ b[0] = 0;
+ for (j = 0; j < 8 && j < (len - i * 8); j++)
+ sprintf(b+strlen(b), " %02x", base[j]);
+ _log("\t\t%04x/@%p:%s\n", 8 * i, base, b);
+ }
+}
+
krb5_error_code
gss_krb5int_make_seal_token_v3 (krb5_context context,
krb5_gss_ctx_id_rec *ctx,
- gss_buffer_t message,
+ const gss_buffer_desc * message,
gss_buffer_t token,
int conf_req_flag, int toktype)
{
- size_t bufsize = 16, cksumsize;
- unsigned char *outbuf = 0, *tmpbuf = 0;
+ size_t bufsize = 16;
+ unsigned char *outbuf = 0;
krb5_error_code err;
int key_usage;
unsigned char acceptor_flag;
- gss_buffer_desc *message2 = message;
+ const gss_buffer_desc *message2 = message;
size_t rrc, ec;
unsigned short tok_id;
-
- static const gss_buffer_desc empty_message = { 0, 0 };
+ krb5_checksum sum;
assert(toktype != KG_TOK_SEAL_MSG || ctx->enc != 0);
assert(ctx->big_endian == 0);
acceptor_flag = ctx->initiate ? 0 : 0x80;
key_usage = (toktype == KG_TOK_WRAP_MSG
- ? (ctx->initiate ? KG_USAGE_INITIATOR_SIGN : KG_USAGE_ACCEPTOR_SIGN)
- : (ctx->initiate ? KG_USAGE_INITIATOR_SEAL : KG_USAGE_ACCEPTOR_SEAL));
+ ? (ctx->initiate
+ ? KG_USAGE_INITIATOR_SIGN
+ : KG_USAGE_ACCEPTOR_SIGN)
+ : (ctx->initiate
+ ? KG_USAGE_INITIATOR_SEAL
+ : KG_USAGE_ACCEPTOR_SEAL));
+
+#define SFILE (strrchr(__FILE__,'/') ? 1+strrchr(__FILE__,'/') : __FILE__)
+
+ _log("%s:%d: wrap input token: %d @%p toktype=0x%x\n", SFILE, __LINE__,
+ message->length, message->value, toktype);
+
+ {
+ static int initialized = 0;
+ if (!initialized) {
+ srand(time(0));
+ initialized = 1;
+ }
+ }
if (toktype == KG_TOK_WRAP_MSG && conf_req_flag) {
krb5_data plain;
if (ec_max > 0xffff)
ec_max = 0xffff;
/* For testing only. For performance, always set ec = 0. */
+#define rand() ((rand)() & 0xf)
ec = ec_max & rand();
+ _log("%s:%d: ec=%d\n", SFILE, __LINE__, ec);
plain.length = message->length + 16 + ec;
plain.data = malloc(message->length + 16 + ec);
if (plain.data == NULL)
store_16_be(0x0504, outbuf);
/* flags */
/* no acceptor subkey stuff yet */
- outbuf[2] = acceptor_flag | (conf_req_flag ? 0x80 : 0);
+ outbuf[2] = acceptor_flag | (conf_req_flag ? 0x40 : 0);
/* filler */
outbuf[3] = 0xff;
/* EC */
plain.data = 0;
if (err)
goto error;
+ _log("%s:%d: just encrypted:\n"
+ "\t(key=%d/%02x%02x..., usage=%d, plain.length=%d,\n"
+ "\t ciphertext=%d/%02x%02x...)\n",
+ SFILE, __LINE__, ctx->enc->enctype,
+ ctx->enc->contents[0], ctx->enc->contents[1],
+ key_usage, plain.length,
+ cipher.ciphertext.length,
+ 0xff & cipher.ciphertext.data[0],
+ 0xff & cipher.ciphertext.data[1]);
/* Now that we know we're returning a valid token.... */
ctx->seq_send++;
/* If the rotate fails, don't worry about it. */
} else if (toktype == KG_TOK_WRAP_MSG && !conf_req_flag) {
krb5_data plain;
- krb5_checksum sum;
/* Here, message is the application-supplied data; message2 is
what goes into the output token. They may be the same, or
if (plain.data == NULL)
return ENOMEM;
- err = krb5_c_checksum_length (context, ctx->cksumtype, &cksumsize);
- if (err) {
- free(plain.data);
- plain.data = 0;
- goto error;
- }
- if (cksumsize > 0xffff)
+ _log("%s:%d: cksumtype=%d\n", SFILE, __LINE__, ctx->cksumtype);
+ if (ctx->cksum_size > 0xffff)
abort();
- bufsize = 16 + message2->length + cksumsize;
+ bufsize = 16 + message2->length + ctx->cksum_size;
outbuf = malloc(bufsize);
if (outbuf == NULL) {
free(plain.data);
}
store_64_be(ctx->seq_send, outbuf+8);
- /* For DEL_CTX, the message is empty, so it doesn't matter
- which path we use. The MIC path will probably change, for
- security reasons. */
- if (toktype != KG_TOK_MIC_MSG) {
- memcpy(plain.data, outbuf, 16);
- memcpy(plain.data + 16, message->value, message->length);
- } else {
- memcpy(plain.data, message->value, message->length);
- memcpy(plain.data+message->length, outbuf, 16);
- }
- sum.length = cksumsize;
- sum.contents = outbuf + 16;
+ memcpy(plain.data, message->value, message->length);
+ memcpy(plain.data + message->length, outbuf, 16);
+
+ /* Fill in the output token -- data contents, if any, and
+ space for the checksum. */
+ if (message2->length)
+ memcpy(outbuf + 16, message2->value, message2->length);
+
+ sum.contents = outbuf + 16 + message2->length;
+ sum.length = ctx->cksum_size;
+ _log("%s:%d: checksum @%p outbuf @%p offset %d\n", SFILE, __LINE__,
+ sum.contents, outbuf, sum.contents - outbuf);
+ _log_block(SFILE, __LINE__, "checksum input",
+ plain.data, plain.length);
err = krb5_c_make_checksum(context, ctx->cksumtype, ctx->enc,
key_usage, &plain, &sum);
-
+ zap(plain.data, plain.length);
+ free(plain.data);
+ plain.data = 0;
+ if (err) {
+ zap(outbuf,bufsize);
+ free(outbuf);
+ goto error;
+ }
+ _log_block(SFILE, __LINE__, "checksum result",
+ sum.contents, sum.length);
+ if (sum.length != ctx->cksum_size)
+ abort();
+ memcpy(outbuf + 16 + message2->length, sum.contents, ctx->cksum_size);
+ krb5_free_checksum_contents(context, &sum);
+ sum.contents = 0;
+ /* Now that we know we're actually generating the token... */
ctx->seq_send++;
- rrc = rand() & 0xffff;
- /* If the rotate fails, don't worry about it. */
- if (rotate_left(outbuf+16, bufsize-16,
- (bufsize-16) - (rrc % (bufsize - 16))))
- store_16_be(rrc, outbuf+6);
-
- /* Fix up EC field. */
- if (toktype == KG_TOK_WRAP_MSG)
- store_16_be(cksumsize, outbuf+4);
+ if (toktype == KG_TOK_WRAP_MSG) {
+ rrc = rand() & 0xffff;
+ /* If the rotate fails, don't worry about it. */
+ if (rotate_left(outbuf+16, bufsize-16,
+ (bufsize-16) - (rrc % (bufsize - 16))))
+ store_16_be(rrc, outbuf+6);
+ /* Fix up EC field. */
+ store_16_be(ctx->cksum_size, outbuf+4);
+ } else {
+ store_16_be(0xffff, outbuf+6);
+ }
} else if (toktype == KG_TOK_MIC_MSG) {
tok_id = 0x0404;
message2 = &empty_message;
} else
abort();
-#if 0
- case KG_TOK_MIC_MSG:
- store_16_be(0x0404, outbuf);
- mic_del_common:
- {
- krb5_checksum sum;
- krb5_data plain;
-
- outbuf[2] = acceptor_flag;
- memset(outbuf+3, 0xff, 5);
- store_64_be(ctx->seq, outbuf + 8);
- sum.length = cksumsize;
- sum.contents = outbuf + 16;
- plain.length = 16 + message2->length;
- tmpbuf = malloc(plain.length);
- if (tmpbuf == NULL) {
- err = ENOMEM;
- goto error;
- }
- plain.data = tmpbuf;
- memcpy(plain.data, outbuf, 16);
- memcpy(plain.data + 16, message2->value, message2->length);
- err = krb5_c_make_checksum(context, ctx->cksumtype, ctx->enc,
- sign_usage, &plain, &sum);
- if (err)
- goto error;
- }
- break;
-#endif
-
- free(tmpbuf);
token->value = outbuf;
token->length = bufsize;
+ _log_block(SFILE, __LINE__, "output token", token->value, token->length);
return 0;
error:
- free(tmpbuf);
free(outbuf);
token->value = NULL;
token->length = 0;
return err;
}
+
+/* message_buffer is an input if SIGN, output if SEAL, and ignored if DEL_CTX
+ conf_state is only valid if SEAL. */
+
+OM_uint32
+gss_krb5int_unseal_token_v3(krb5_context *contextptr,
+ OM_uint32 *minor_status,
+ 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_context context = *contextptr;
+ krb5_data plain;
+ gssint_uint64 seqnum;
+ size_t ec, rrc;
+ int key_usage;
+ unsigned char acceptor_flag;
+ krb5_checksum sum;
+ krb5_error_code err;
+ krb5_boolean valid;
+
+ assert(toktype != KG_TOK_SEAL_MSG || ctx->enc != 0);
+ assert(ctx->big_endian == 0);
+ assert(ctx->proto == 1);
+
+ if (qop_state)
+ *qop_state = GSS_C_QOP_DEFAULT;
+
+ acceptor_flag = ctx->initiate ? FLAG_SENDER_IS_ACCEPTOR : 0;
+ key_usage = (toktype == KG_TOK_WRAP_MSG
+ ? (!ctx->initiate
+ ? KG_USAGE_INITIATOR_SIGN
+ : KG_USAGE_ACCEPTOR_SIGN)
+ : (!ctx->initiate
+ ? KG_USAGE_INITIATOR_SEAL
+ : KG_USAGE_ACCEPTOR_SEAL));
+
+#define LOG() _log("%s:%d: here\n", SFILE, __LINE__)
+#define DEFECTIVE do{LOG();goto defective;}while(0)
+
+ _log ("%s:%d: bodysize %d ptr @%p: %02x %02x\n", SFILE, __LINE__,
+ bodysize, ptr, ptr[0], ptr[1]);
+
+ /* Oops. I wrote this code assuming ptr would be at the start of
+ the token header. */
+ ptr -= 2;
+ bodysize += 2;
+
+ _log_block(SFILE, __LINE__, "input token", ptr, bodysize);
+
+ if (bodysize < 16) {
+ LOG();
+ defective:
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+ LOG();
+ if ((ptr[2] & FLAG_SENDER_IS_ACCEPTOR) != acceptor_flag) {
+ *minor_status = G_BAD_DIRECTION;
+ return GSS_S_BAD_SIG;
+ }
+ LOG();
+ if (toktype == KG_TOK_WRAP_MSG) {
+ if (load_16_be(ptr) != 0x0504)
+ DEFECTIVE;
+ if (ptr[2] & ~0xe0)
+ DEFECTIVE;
+ if (ptr[3] != 0xff)
+ DEFECTIVE;
+ ec = load_16_be(ptr+4);
+ rrc = load_16_be(ptr+6);
+ seqnum = load_64_be(ptr+8);
+ if (!rotate_left(ptr+16, bodysize-16, rrc)) {
+ no_mem:
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ if (ptr[2] & FLAG_WRAP_CONFIDENTIAL) {
+ /* confidentiality */
+ krb5_enc_data cipher;
+ unsigned char *althdr;
+
+ LOG();
+ if (conf_state)
+ *conf_state = 1;
+ /* Do we have no decrypt_size function?
+
+ For all current cryptosystems, the ciphertext size will
+ be larger than the plaintext size. */
+ cipher.enctype = ctx->enc->enctype;
+ cipher.ciphertext.length = bodysize - 16;
+ cipher.ciphertext.data = ptr + 16;
+ plain.length = bodysize - 16;
+ plain.data = malloc(plain.length);
+ if (plain.data == NULL)
+ goto no_mem;
+ _log("%s:%d: about to decrypt:\n"
+ "\t(key=%d/%02x%02x..., usage=%d, ciphertext=%d/%02x%02x...)\n",
+ SFILE, __LINE__, ctx->enc->enctype,
+ ctx->enc->contents[0], ctx->enc->contents[1],
+ key_usage,
+ cipher.ciphertext.length,
+ 0xff & cipher.ciphertext.data[0],
+ 0xff & cipher.ciphertext.data[1]);
+ err = krb5_c_decrypt(context, ctx->enc, key_usage, 0,
+ &cipher, &plain);
+ if (err) {
+ free(plain.data);
+ _log("%s:%d: error %ld/%s\n", SFILE, __LINE__,
+ (long) err, error_message(err));
+ goto error;
+ }
+ /* Don't use bodysize here! Use the fact that
+ cipher.ciphertext.length has been adjusted to the
+ correct length. */
+ LOG();
+ althdr = plain.data + plain.length - 16;
+ if (load_16_be(althdr) != 0x0504
+ || althdr[2] != ptr[2]
+ || althdr[3] != ptr[3]
+ || memcmp(althdr+8, ptr+8, 8))
+ DEFECTIVE;
+ message_buffer->value = plain.data;
+ _log("%s:%d: plaintext len=%d, ec=%d\n", SFILE, __LINE__,
+ plain.length, ec);
+ message_buffer->length = plain.length - ec - 16;
+ _log("%s:%d: decrypted token %d @%p\n", SFILE, __LINE__,
+ message_buffer->length, message_buffer->value);
+ } else {
+ /* no confidentiality */
+ LOG();
+ if (conf_state)
+ *conf_state = 0;
+ if (ec + 16 < ec)
+ /* overflow check */
+ DEFECTIVE;
+ LOG();
+ if (ec + 16 > bodysize)
+ DEFECTIVE;
+ LOG();
+ /* We have: header | msg | cksum.
+ We need cksum(msg | header).
+ Rotate the first two. */
+ store_16_be(0, ptr+4);
+ store_16_be(0, ptr+6);
+ plain.length = bodysize-ec;
+ plain.data = ptr;
+ if (!rotate_left(ptr, bodysize-ec, 16))
+ goto no_mem;
+ sum.length = ec;
+ if (sum.length != ctx->cksum_size) {
+ *minor_status = 0;
+ LOG();
+ return GSS_S_BAD_SIG;
+ }
+ sum.contents = ptr+bodysize-ec;
+ sum.checksum_type = ctx->cksumtype;
+ _log_block(SFILE, __LINE__, "checksum data input",
+ plain.data, plain.length);
+ _log_block(SFILE, __LINE__, "checksum to test",
+ sum.contents, sum.length);
+ err = krb5_c_verify_checksum(context, ctx->enc, key_usage,
+ &plain, &sum, &valid);
+ if (err)
+ goto error;
+ _log("%s:%d: valid=%d\n", SFILE, __LINE__, valid);
+ if (!valid) {
+ LOG();
+ *minor_status = 0;
+ return GSS_S_BAD_SIG;
+ }
+ message_buffer->length = plain.length - 16;
+ message_buffer->value = malloc(message_buffer->length);
+ if (message_buffer->value == NULL)
+ goto no_mem;
+ memcpy(message_buffer->value, plain.data, message_buffer->length);
+ }
+ LOG();
+ err = g_order_check(&ctx->seqstate, seqnum);
+ *minor_status = 0;
+ _log("%s:%d: g_order_check => %d/%s, unseal %s\n", SFILE, __LINE__,
+ err, err ? error_message(err) : "No error",
+ err ? "failed" : "passed");
+ return err;
+ } else if (toktype == KG_TOK_MIC_MSG) {
+ /* wrap token, no confidentiality */
+ LOG();
+ if (load_16_be(ptr) != 0x0404)
+ DEFECTIVE;
+ LOG();
+ verify_mic_1:
+ LOG();
+ if (ptr[2] & ~0xe0)
+ DEFECTIVE;
+ LOG();
+ if (ptr[3] != 0xff)
+ DEFECTIVE;
+ _log("%s:%d: at ptr+4 %p: %02x %02x %02x %02x\n", SFILE, __LINE__,
+ ptr+4, ptr[4], ptr[5], ptr[6], ptr[7]);
+ if (load_32_be(ptr+4) != 0xffffffffL)
+ DEFECTIVE;
+ LOG();
+ seqnum = load_64_be(ptr+8);
+ plain.length = message_buffer->length + 16;
+ plain.data = malloc(plain.length);
+ if (plain.data == NULL)
+ goto no_mem;
+ if (message_buffer->length)
+ memcpy(plain.data, message_buffer->value, message_buffer->length);
+ memcpy(plain.data + message_buffer->length, ptr, 16);
+ sum.length = bodysize - 16;
+ sum.contents = ptr + 16;
+ sum.checksum_type = ctx->cksumtype;
+ _log("%s:%d: sum.length = %d\n", SFILE, __LINE__, sum.length);
+ _log_block(SFILE, __LINE__, "checksum data input",
+ plain.data, plain.length);
+ _log_block(SFILE, __LINE__, "checksum to test",
+ sum.contents, sum.length);
+ err = krb5_c_verify_checksum(context, ctx->enc, key_usage,
+ &plain, &sum, &valid);
+ if (err) {
+ error:
+ free(plain.data);
+ LOG();
+ *minor_status = err;
+ return GSS_S_BAD_SIG; /* XXX */
+ }
+ LOG();
+ if (!valid) {
+ free(plain.data);
+ *minor_status = 0;
+ LOG();
+ return GSS_S_BAD_SIG;
+ }
+ LOG();
+ err = g_order_check(&ctx->seqstate, seqnum);
+ *minor_status = 0;
+ return err;
+ } else if (toktype == KG_TOK_DEL_CTX) {
+ LOG();
+ if (load_16_be(ptr) != 0x0405)
+ DEFECTIVE;
+ LOG();
+ message_buffer = &empty_message;
+ goto verify_mic_1;
+ } else {
+ LOG();
+ DEFECTIVE;
+ }
+}
unsigned char *ptr;
unsigned int bodysize;
int err;
+ int toktype2;
+
+ _log_block2("token to unseal",
+ input_token_buffer->value, input_token_buffer->length);
/* validate the context handle */
if (! kg_validate_ctx_id(context_handle)) {
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))) {
- return(kg_unseal_v1(context, minor_status, ctx, ptr, bodysize,
- message_buffer, conf_state, qop_state,
- toktype));
+ if (ctx->proto)
+ switch (toktype) {
+ case KG_TOK_SIGN_MSG:
+ toktype2 = 0x0404;
+ break;
+ case KG_TOK_SEAL_MSG:
+ toktype2 = 0x0504;
+ break;
+ case KG_TOK_DEL_CTX:
+ toktype2 = 0x0405;
+ break;
+ default:
+ toktype2 = toktype;
+ break;
+ }
+ else
+ toktype2 = toktype;
+ err = g_verify_token_header((gss_OID) ctx->mech_used,
+ &bodysize, &ptr, toktype2,
+ input_token_buffer->length,
+ !ctx->proto);
+ if (err) {
+ *minor_status = err;
+ _log("%s:%d: g_verify_token_header returns %d/%s\n", SFILE, __LINE__,
+ err, error_message(err));
+ return GSS_S_DEFECTIVE_TOKEN;
}
- *minor_status = err;
- return(GSS_S_DEFECTIVE_TOKEN);
+ if (ctx->proto == 0)
+ return kg_unseal_v1(context, minor_status, ctx, ptr, bodysize,
+ message_buffer, conf_state, qop_state,
+ toktype);
+ else
+ return gss_krb5int_unseal_token_v3(context, minor_status, ctx,
+ ptr, bodysize, message_buffer,
+ conf_state, qop_state, toktype);
}
int *conf_state;
int *qop_state;
{
+ _log("%s:%d: input length %d\n", SFILE, __LINE__,
+ input_message_buffer->length);
+ if (input_message_buffer->length == 0) {
+ if (fork() == 0)
+ abort();
+ }
return(krb5_gss_unseal(minor_status, context_handle,
input_message_buffer, output_message_buffer,
conf_state, qop_state));
/* "unseal" the token */
+ _log("%s:%d: here\n", SFILE, __LINE__);
if (GSS_ERROR(majerr = kg_unseal(context, minor_status, ctx, token_buffer,
GSS_C_NO_BUFFER, NULL, NULL,
KG_TOK_DEL_CTX)))
return(majerr);
+ _log("%s:%d: here\n", SFILE, __LINE__);
/* that's it. delete the context */
if ((ctx = (krb5_gss_ctx_id_rec *) arg)) {
required = 16*sizeof(krb5_int32);
required += sizeof(ctx->seed);
- required += ctx->nctypes*sizeof(krb5_int32);
kret = 0;
if (!kret && ctx->here)
&bp, &remain);
(void) krb5_ser_pack_int32((krb5_int32) ctx->krb_flags,
&bp, &remain);
- (void) krb5_ser_pack_int32((krb5_int32) ctx->seq_send,
+ (void) krb5_ser_pack_int64((krb5_int64) ctx->seq_send,
&bp, &remain);
- (void) krb5_ser_pack_int32((krb5_int32) ctx->seq_recv,
+ (void) krb5_ser_pack_int64((krb5_int64) ctx->seq_recv,
&bp, &remain);
(void) krb5_ser_pack_int32((krb5_int32) ctx->established,
&bp, &remain);
(void) krb5_ser_pack_int32((krb5_int32) ctx->big_endian,
&bp, &remain);
- (void) krb5_ser_pack_int32((krb5_int32) ctx->nctypes,
- &bp, &remain);
/* Now dynamic data */
kret = 0;
(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);
*buffer = bp;
ctx->endtime = (krb5_timestamp) ibuf;
(void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
ctx->krb_flags = (krb5_flags) ibuf;
- (void) krb5_ser_unpack_int32(&ctx->seq_send, &bp, &remain);
- (void) krb5_ser_unpack_int32(&ctx->seq_recv, &bp, &remain);
+ (void) krb5_ser_unpack_int64(&ctx->seq_send, &bp, &remain);
+ (void) krb5_ser_unpack_int64(&ctx->seq_recv, &bp, &remain);
(void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
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->nctypes = (int) ibuf;
if ((kret = kg_oid_internalize(kcontext, &ctx->mech_used, &bp,
&remain))) {
KV5M_AUTH_CONTEXT,
(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 &&
if (GSS_ERROR(kg_get_context(minor_status, &context)))
return(GSS_S_FAILURE);
+ _log_block2("krb5_gss_unseal token", input_message_buffer->value,
+ input_message_buffer->length);
return(kg_unseal(context, minor_status, context_handle,
input_message_buffer, output_message_buffer,
conf_state, qop_state, KG_TOK_SEAL_MSG));
if (GSS_ERROR(kg_get_context(minor_status, &context)))
return(GSS_S_FAILURE);
+ _log("%s:%d: here\n", SFILE, __LINE__);
rstat = kg_unseal(context, minor_status, context_handle,
input_message_buffer, output_message_buffer,
conf_state, &qstate, KG_TOK_WRAP_MSG);
+ _log("%s:%d: here\n", SFILE, __LINE__);
if (!rstat && qop_state)
*qop_state = (gss_qop_t) qstate;
return(rstat);
return(GSS_S_FAILURE);
+ _log("%s:%d: here\n", SFILE, __LINE__);
return(kg_unseal(context, minor_status, context_handle,
token_buffer, message_buffer,
NULL, qop_state, KG_TOK_SIGN_MSG));
{
krb5_context context;
OM_uint32 rstat;
- int qstate;
+ OM_uint32 qstate;
if (GSS_ERROR(kg_get_context(minor_status, &context)))
return(GSS_S_FAILURE);
+ _log("%s:%d: here\n", SFILE, __LINE__);
rstat = kg_unseal(context, minor_status, context_handle,
token_buffer, message_buffer,
NULL, &qstate, KG_TOK_MIC_MSG);
+ _log("%s:%d: here\n", SFILE, __LINE__);
if (!rstat && qop_state)
*qop_state = (gss_qop_t) qstate;
return(rstat);
return(GSS_S_NO_CONTEXT);
}
+#if 1
+ if (ctx->proto == 1) {
+ /* No pseudo-ASN.1 wrapper overhead, so no sequence length and
+ OID. */
+ OM_uint32 sz = req_output_size;
+ /* Token header: 16 octets. */
+ if (conf_req_flag) {
+ while (sz > 0 && krb5_encrypt_size(sz, ctx->enc->enctype) + 16 > req_output_size)
+ sz--;
+ } else {
+ if (sz < 16 + ctx->cksum_size)
+ sz = 0;
+ else
+ sz -= (16 + ctx->cksum_size);
+ }
+ *max_input_size = sz;
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+ }
+#endif
+
/* Calculate the token size and subtract that from the output size */
overhead = 7 + ctx->mech_used->length;
data_size = req_output_size;
-1
};
-static krb5_enctype enctypes[] = {
- ENCTYPE_DES3_CBC_SHA1,
- ENCTYPE_ARCFOUR_HMAC,
- ENCTYPE_DES_CBC_MD5,
- ENCTYPE_DES_CBC_CRC,
- 0,
-};
+static const krb5_enctype *enctypes = 0;
static kadm5_ret_t _kadm5_init_any(char *client_name,
enum init_type init_type,
CLIENT *clnt;
{
static generic_ret res;
+ int x;
memset((char *)&res, 0, sizeof(res));
- if (clnt_call(clnt, INIT, xdr_u_int32, argp,
- xdr_generic_ret, &res, TIMEOUT) != RPC_SUCCESS) {
+ x = clnt_call(clnt, INIT, xdr_u_int32, argp,
+ xdr_generic_ret, &res, TIMEOUT);
+ if (x != RPC_SUCCESS) {
+ _log("%s:%d: init_1: clnt_call returned %d\n", SFILE, __LINE__, x);
return (NULL);
}
return (&res);
krb5_error_code krb5_ktkdb_get_entry (krb5_context, krb5_keytab, krb5_const_principal,
krb5_kvno, krb5_enctype, krb5_keytab_entry *);
+static krb5_error_code
+krb5_ktkdb_get_name(krb5_context context, krb5_keytab keytab,
+ char *name, unsigned int namelen)
+{
+ if (namelen < sizeof("KDB:"))
+ return KRB5_KT_NAME_TOOLONG;
+ strcpy(name, "KDB:");
+ return 0;
+}
+
krb5_kt_ops krb5_kt_kdb_ops = {
0,
"KDB", /* Prefix -- this string should not appear anywhere else! */
krb5_ktkdb_resolve, /* resolve */
- NULL, /* get_name */
+ krb5_ktkdb_get_name, /* get_name */
krb5_ktkdb_close, /* close */
krb5_ktkdb_get_entry, /* get */
NULL, /* start_seq_get */
PRINTF(("gssapi_marshall: sending seq_num %d\n", seq_num));
+ _log("%s:%d: in %s\n", SFILE, __LINE__, __func__);
if (auth_gssapi_seal_seq(AUTH_PRIVATE(auth)->context, seq_num,
&out_buf) == FALSE) {
PRINTF(("gssapi_marhshall: seal failed\n"));
}
-
+ _log("%s:%d: in %s\n", SFILE, __LINE__, __func__);
+
auth->ah_verf.oa_base = out_buf.value;
auth->ah_verf.oa_length = out_buf.length;
in_buf.length = sizeof(rpc_u_int32);
in_buf.value = (char *) &nl_seq_num;
+ _log("%s:%d: %s about to call gss_seal\n", SFILE, __LINE__,
+ __func__);
gssstat = gss_seal(&minor_stat, context, 0, GSS_C_QOP_DEFAULT,
&in_buf, NULL, out_buf);
+ _log("%s:%d: %s result %d/%d in_buf %d out_buf %d\n", __FILE__, __LINE__,
+ __func__, gssstat, minor_stat, in_buf.length, out_buf->length);
if (gssstat != GSS_S_COMPLETE) {
PRINTF(("gssapi_seal_seq: failed\n"));
AUTH_GSSAPI_DISPLAY_STATUS(("sealing sequence number",
gssstat = gss_unseal(&minor_stat, context, in_buf, &out_buf,
NULL, NULL);
+ _log("%s:%d: %s input len %d result %d/%d len %d\n",
+ __FILE__, __LINE__, __func__, in_buf->length,
+ gssstat, minor_stat, out_buf.length);
if (gssstat != GSS_S_COMPLETE) {
PRINTF(("gssapi_unseal_seq: failed\n"));
AUTH_GSSAPI_DISPLAY_STATUS(("unsealing sequence number",
return (0);
#endif /* def FD_SETSIZE */
+#define SFILE (strrchr(__FILE__,'/') ? 1+strrchr(__FILE__,'/') : __FILE__)
while (TRUE) {
readfds = mask;
tout = ct->ct_wait;
&tout)) {
case 0:
ct->ct_error.re_status = RPC_TIMEDOUT;
+ _log("%s:%d: %s select says 0\n", SFILE, __LINE__, __func__);
+ if (fork() == 0) abort();
return (-1);
case -1:
continue;
ct->ct_error.re_status = RPC_CANTRECV;
ct->ct_error.re_errno = errno;
+ _log("%s:%d: %s select says error %d/%s\n", SFILE, __LINE__, __func__,
+ errno, error_message(errno));
return (-1);
}
break;
switch (len = read(ct->ct_sock, buf, (size_t) len)) {
case 0:
+ _log("%s:%d: %s %d bytes\n", SFILE, __LINE__, __func__, len);
/* premature eof */
ct->ct_error.re_errno = ECONNRESET;
ct->ct_error.re_status = RPC_CANTRECV;
break;
case -1:
+ _log("%s:%d: %s %d bytes\n", SFILE, __LINE__, __func__, len);
ct->ct_error.re_errno = errno;
ct->ct_error.re_status = RPC_CANTRECV;
break;
+ default:
+ _log("%s:%d: %s %d bytes\n", SFILE, __LINE__, __func__, len);
}
return (len);
}
for (cnt = len; cnt > 0; cnt -= i, buf += i) {
if ((i = write(ct->ct_sock, buf, (size_t) cnt)) == -1) {
+ _log("%s:%d: %s %d bytes\n", SFILE, __LINE__, __func__, len);
ct->ct_error.re_errno = errno;
ct->ct_error.re_status = RPC_CANTSEND;
return (-1);
}
+ _log("%s:%d: %s %d bytes\n", SFILE, __LINE__, __func__, len);
}
return (len);
}
buf += RNDUP(oa->oa_length) / sizeof (rpc_int32);
}
oa = &cmsg->rm_call.cb_verf;
+ _log("%s:%d: packing: oa->oa_flavor=%d oa_length=%d\n",
+ __FILE__, __LINE__, oa->oa_flavor, oa->oa_length);
IXDR_PUT_ENUM(buf, oa->oa_flavor);
IXDR_PUT_LONG(buf, oa->oa_length);
if (oa->oa_length) {
oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t);
oa->oa_length = IXDR_GET_LONG(buf);
}
+ _log("%s:%d: unpacked: oa->oa_flavor=%d oa_length=%d\n",
+ __FILE__, __LINE__, oa->oa_flavor, oa->oa_length);
if (oa->oa_length) {
if (oa->oa_length > MAX_AUTH_BYTES) {
return (FALSE);
no_dispatch = FALSE;
/* first authenticate the message */
+ _log("%s:%d: msg.cb_verf.oa_length=%d, oa_flavor=%d\n",
+ __FILE__, __LINE__, msg.rm_call.cb_verf.oa_length,
+ msg.rm_call.cb_verf.oa_flavor);
why=_authenticate(&r, &msg, &no_dispatch);
if (why != AUTH_OK) {
svcerr_auth(xprt, why);
rqst->rq_xprt->xp_verf.oa_length = 0;
cred_flavor = rqst->rq_cred.oa_flavor;
*no_dispatch = FALSE;
+ _log("%s:%d: dispatching authentication flavor %d\n",
+ __FILE__, __LINE__, cred_flavor);
for (i = 0; i < svcauthnum; i++) {
if (cred_flavor == svcauthsw[i].flavor &&
svcauthsw[i].authenticator != NULL) {
rpc_u_int32 seq_num;
PRINTF(("svcauth_gssapi: starting\n"));
+ _log("%s:%d: svcauth_gssapi starting\n", __FILE__, __LINE__);
/* clean up expired entries */
clean_client();
#ifdef DEBUG_GSSAPI
if (svc_debug_gssapi) {
if (creds.auth_msg && rqst->rq_proc == AUTH_GSSAPI_EXIT) {
+ _log("%s:%d: %s AUTH_GSSAPI_EXIT\n", SFILE, __LINE__, __func__);
PRINTF(("svcauth_gssapi: GSSAPI_EXIT, cleaning up\n"));
svc_sendreply(rqst->rq_xprt, xdr_void, NULL);
gssrpc_xdr_free(xdr_authgssapi_creds, &creds);
PRINTF(("svcauth_gssapi: context established, isn %d\n",
client_data->seq_num));
+ _log("%s:%d: in %s\n", SFILE, __LINE__, __func__);
if (auth_gssapi_seal_seq(client_data->context,
client_data->seq_num,
&call_res.signed_isn) ==
gss_release_buffer(&minor_stat, &output_token);
goto error;
}
+ _log("%s:%d: in %s\n", SFILE, __LINE__, __func__);
}
PRINTF(("svcauth_gssapi: sending reply\n"));
/* prepare response verifier */
seq_num = client_data->seq_num + 1;
+ _log("%s:%d: in %s\n", SFILE, __LINE__, __func__);
if (auth_gssapi_seal_seq(client_data->context, seq_num,
&out_buf) == FALSE) {
ret = AUTH_FAILED;
LOG_MISCERR("internal error sealing sequence number");
goto error;
}
+ _log("%s:%d: in %s\n", SFILE, __LINE__, __func__);
client_data->seq_num++;
+2003-12-02 Ken Raeburn <raeburn@mit.edu>
+
+ * lib/helpers.exp (expect_kadm_ok, eof_client): Accept and ignore
+ debugging messages starting "marshall_new_creds" or "gssapi_", and
+ blank lines.
+
2003-01-07 Ken Raeburn <raeburn@mit.edu>
* Makefile.ov: Deleted.
expect {
-i $kadmin_tcl_spawn_id
-re "^OK OVSEC_KADM_OK \[^\n\]*\n" {}
+ -re "^marshall_new_creds: \[^\n\]*\n" { exp_continue }
+ -re "^gssapi_\[^\n\]*\n" { exp_continue }
+ -re "^\r?\n" { exp_continue }
default { perror "didn't get ok back" }
}
}
expect {
-i $id
+ -re "^marshall_new_creds\[^\n\]*\n" { exp_continue }
+ -re "^gssapi_\[^\n\]*\n" { exp_continue }
+ -re "^\r?\n" { exp_continue }
eof { verbose $expect_out(buffer) 1 }
timeout {
fail "$testname: timeout waiting for client $ccname to exit"
{
register size_t current;
+#define SFILE (strrchr(__FILE__,'/') ? 1+strrchr(__FILE__,'/') : __FILE__)
+ _log("%s:%d: %s wants %d bytes\n", SFILE, __LINE__, __func__, len);
while (len > 0) {
current = (size_t)((long)rstrm->in_boundry -
(long)rstrm->in_finger);
{master_key_type=aes256-cts-hmac-sha1-96}
{dummy=[verbose -log "AES + DES enctypes"]}
}
+ {
+ aesonly
+ des3_krbtgt=0
+ {supported_enctypes=aes256-cts-hmac-sha1-96:normal}
+ {kdc_supported_enctypes=aes256-cts-hmac-sha1-96:normal}
+ {permitted_enctypes(kdc)=aes256-cts-hmac-sha1-96}
+ {permitted_enctypes(client)=aes256-cts-hmac-sha1-96}
+ {permitted_enctypes(server)=aes256-cts-hmac-sha1-96}
+ {master_key_type=aes256-cts-hmac-sha1-96}
+ {dummy=[verbose -log "AES enctypes"]}
+ }
{
aes-des3
des3_krbtgt=0
wait -i $tailf_spawn_id
return 0
}
+ "No principal in keytab matches desired name" {
+ dump_db
+ exp_continue
+ }
"starting" { }
timeout {
if {$standalone} {
}
}
+# dump_db
+proc dump_db { } {
+ global KADMIN_LOCAL
+ global REALMNAME
+
+ spawn $KADMIN_LOCAL -r $REALMNAME
+ expect_after {
+ eof {
+ perror "failed to get debugging dump of database (eof)"
+ }
+ timeout {
+ perror "failed to get debugging dump of database (timeout)"
+ }
+ }
+ expect "kadmin.local: "
+ send "getprincs\r"
+ expect "kadmin.local: "
+ send "quit\r"
+ expect eof
+ catch expect_after
+}
+
# add_random_key
# Add a key with a random password to the Kerberos database.
# start_kerberos_daemons must be called before this procedure. If the
# helpful sometimes for debugging the test suite
proc spawn_xterm { } {
global env
- foreach i {KDB5_UTIL KRB5KDC KADMIND KADMIN KADMIN_LOCAL KINIT KTUTIL KLIST RLOGIN RLOGIND FTP FTPD KPASSWD REALMNAME} {
+ foreach i {KDB5_UTIL KRB5KDC KADMIND KADMIN KADMIN_LOCAL KINIT KTUTIL KLIST RLOGIN RLOGIND FTP FTPD KPASSWD REALMNAME GSSCLIENT REALMNAME} {
global $i
if [info exists $i] { set env($i) [set $i] }
}
set gss_server_spawn_id $spawn_id
sleep 2
+ if 0 {
+ send_user "about to run run_client gssclient0 $tmppwd/gss_tk_0 gssclient0\n"
+ set env(CMD) "env KRB5CCNAME=$tmppwd/gss_tk_0 $GSSCLIENT -port 5556 $hostname gssservice@$hostname message-from-gssclient0"
+ spawn_xterm
+ }
run_client gssclient0 $tmppwd/gss_tk_0 gssclient0
run_client gssclient1 $tmppwd/gss_tk_1 gssclient1
run_client gssclient2 $tmppwd/gss_tk_2 gssclient2