aboutsummaryrefslogtreecommitdiff
path: root/src/lib/gssapi/krb5/k5unseal.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/gssapi/krb5/k5unseal.c')
-rw-r--r--src/lib/gssapi/krb5/k5unseal.c1084
1 files changed, 342 insertions, 742 deletions
diff --git a/src/lib/gssapi/krb5/k5unseal.c b/src/lib/gssapi/krb5/k5unseal.c
index da5966f..bc35e70 100644
--- a/src/lib/gssapi/krb5/k5unseal.c
+++ b/src/lib/gssapi/krb5/k5unseal.c
@@ -1,6 +1,6 @@
/*
* Copyright 1993 by OpenVision Technologies, Inc.
- *
+ *
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appears in all copies and
@@ -10,7 +10,7 @@
* without specific, written prior permission. OpenVision makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
- *
+ *
* OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
@@ -22,14 +22,14 @@
/*
* 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
@@ -40,7 +40,7 @@
* 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.
@@ -51,838 +51,438 @@
#include <memory.h>
#endif
-/*
- * $Id$
- */
+/* message_buffer is an input if SIGN, output if SEAL, and ignored if DEL_CTX
+ conf_state is only valid if SEAL. */
-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;
+OM_uint32
+kg_unseal_v1(context, minor_status, ctx, ptr, bodysize, message_buffer,
+ conf_state, qop_state, toktype)
+ krb5_context context;
+ 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;
{
- size_t cksumlen;
krb5_error_code code;
- krb5_data plain;
- krb5_cksumtype tctype;
- krb5_ui_4 tseqnum;
- int tdirection;
+ int tmsglen;
+ int conflen = 0;
+ int signalg;
+ int sealalg;
+ gss_buffer_desc token;
krb5_checksum cksum;
- krb5_boolean ckvalid;
+ krb5_checksum md5cksum;
+ krb5_data plaind;
+ char *data_ptr;
krb5_timestamp now;
+ unsigned char *plain;
+ int cksum_len = 0;
+ int plainlen;
+ int direction;
+ krb5_int32 seqnum;
OM_uint32 retval;
+ size_t sumlen;
- 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);
+ if (toktype == KG_TOK_SEAL_MSG) {
+ message_buffer->length = 0;
+ message_buffer->value = NULL;
}
- /* allocate the checksum buffer */
-
- plain.length = 7+text->length;
+ /* get the sign and seal algorithms */
- if ((plain.data = (char *) malloc(plain.length)) == NULL) {
- *minor_status = ENOMEM;
- return(GSS_S_FAILURE);
- }
+ signalg = ptr[0] + (ptr[1]<<8);
+ sealalg = ptr[2] + (ptr[3]<<8);
- /* suck out the body parts from the token */
+ /* Sanity checks */
- 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);
+ if ((ptr[4] != 0xff) || (ptr[5] != 0xff)) {
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
}
- cksum.contents = ptr;
- cksum.checksum_type = tctype;
+ if ((toktype != KG_TOK_SEAL_MSG) &&
+ (sealalg != 0xffff)) {
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
- /* finish assembling the checksum buffer and compute the checksum */
+ /* in the current spec, there is only one valid seal algorithm per
+ key type, so a simple comparison is ok */
- plain.data[5] = (text->length >> 8) & 0xff;
- plain.data[6] = text->length & 0xff;
+ if ((toktype == KG_TOK_SEAL_MSG) &&
+ !((sealalg == 0xffff) ||
+ (sealalg == ctx->sealalg))) {
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
- memcpy(plain.data+7, text->value, text->length);
+ /* there are several mappings of seal algorithms to sign algorithms,
+ but few enough that we can try them all. */
- 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 ((ctx->sealalg == SEAL_ALG_NONE && signalg > 1) ||
+ (ctx->sealalg == SEAL_ALG_1 && signalg != SGN_ALG_3) ||
+ (ctx->sealalg == SEAL_ALG_DES3KD &&
+ signalg != SGN_ALG_HMAC_SHA1_DES3_KD)) {
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
}
- if (!ckvalid) {
- free(plain.data);
+ switch (signalg) {
+ case SGN_ALG_DES_MAC_MD5:
+ case SGN_ALG_MD2_5:
+ cksum_len = 8;
+ break;
+ case SGN_ALG_3:
+ cksum_len = 16;
+ break;
+ case SGN_ALG_HMAC_SHA1_DES3_KD:
+ cksum_len = 20;
+ break;
+ default:
*minor_status = 0;
- return(GSS_S_BAD_SIG);
+ return GSS_S_DEFECTIVE_TOKEN;
}
- /* check context expiry */
+ if (toktype == KG_TOK_SEAL_MSG)
+ tmsglen = bodysize-(14+cksum_len);
- if ((code = krb5_timeofday(context, &now))) {
- free(plain.data);
- *minor_status = code;
- return(GSS_S_FAILURE);
- }
+ /* get the token parameters */
- if (now > ctx->endtime) {
- free(plain.data);
- *minor_status = 0;
- return(GSS_S_CONTEXT_EXPIRED);
- }
+ /* decode the message, if SEAL */
- /* do sequencing checks */
+ if (toktype == KG_TOK_SEAL_MSG) {
+ if (sealalg != 0xffff) {
+ if ((plain = (unsigned char *) xmalloc(tmsglen)) == NULL) {
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
- if ((ctx->initiate && tdirection != 0xff) ||
- (!ctx->initiate && tdirection != 0)) {
- free(plain.data);
- *minor_status = G_BAD_DIRECTION;
- return(GSS_S_BAD_SIG);
- }
+ if ((code = kg_decrypt(context, ctx->enc, KG_USAGE_SEAL, NULL,
+ ptr+14+cksum_len, plain, tmsglen))) {
+ xfree(plain);
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
+ } else {
+ plain = ptr+14+cksum_len;
+ }
- retval = g_order_check(&(ctx->seqstate), tseqnum);
+ plainlen = tmsglen;
- free(plain.data);
+ if ((sealalg == 0xffff) && ctx->big_endian) {
+ token.length = tmsglen;
+ } else {
+ conflen = kg_confounder_size(context, ctx->enc);
+ token.length = tmsglen - conflen - plain[tmsglen-1];
+ }
- if (retval) {
- *minor_status = 0;
- return(retval);
- }
+ if (token.length) {
+ if ((token.value = (void *) xmalloc(token.length)) == NULL) {
+ if (sealalg != 0xffff)
+ xfree(plain);
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+ memcpy(token.value, plain+conflen, token.length);
+ }
+ } else if (toktype == KG_TOK_SIGN_MSG) {
+ token = *message_buffer;
+ plain = token.value;
+ plainlen = token.length;
+ } else {
+ token.length = 0;
+ token.value = NULL;
+ plain = token.value;
+ plainlen = token.length;
+ }
- if (qop_state)
- *qop_state = GSS_C_QOP_DEFAULT;
+ /* compute the checksum of the message */
+
+ /* initialize the the cksum */
+ switch (signalg) {
+ case SGN_ALG_DES_MAC_MD5:
+ case SGN_ALG_MD2_5:
+ case SGN_ALG_HMAC_MD5:
+ case SGN_ALG_DES_MAC:
+ case SGN_ALG_3:
+ md5cksum.checksum_type = CKSUMTYPE_RSA_MD5;
+ break;
+ case SGN_ALG_HMAC_SHA1_DES3_KD:
+ md5cksum.checksum_type = CKSUMTYPE_HMAC_SHA1_DES3;
+ break;
+ default:
+ abort ();
+ }
- *minor_status = 0;
- return(GSS_S_COMPLETE);
-}
+ if (code = krb5_c_checksum_length(context, md5cksum.checksum_type, &sumlen))
+ return(code);
+ md5cksum.length = sumlen;
-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;
+ switch (signalg) {
+ case SGN_ALG_DES_MAC_MD5:
+ case SGN_ALG_3:
+ /* compute the checksum of the message */
- output->length = 0;
- output->value = NULL;
+ /* 8 = bytes of token body to be checksummed according to spec */
- /* read the body parts out of the message */
+ if (! (data_ptr = (void *)
+ xmalloc(8 + (ctx->big_endian ? token.length : plainlen)))) {
+ if (sealalg != 0xffff)
+ xfree(plain);
+ if (toktype == KG_TOK_SEAL_MSG)
+ xfree(token.value);
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
- if (bodysize < 11) {
- *minor_status = G_TOK_TRUNC;
- return(GSS_S_DEFECTIVE_TOKEN);
- }
+ (void) memcpy(data_ptr, ptr-2, 8);
+
+ if (ctx->big_endian)
+ (void) memcpy(data_ptr+8, token.value, token.length);
+ else
+ (void) memcpy(data_ptr+8, plain, plainlen);
- tcksum.checksum_type = (krb5_cksumtype) ((ptr[0]<<24) | (ptr[1]<<16) |
- (ptr[2]<<8) | ptr[3]);
- ptr += 4;
+ plaind.length = 8 + (ctx->big_endian ? token.length : plainlen);
+ plaind.data = data_ptr;
+ code = krb5_c_make_checksum(context, md5cksum.checksum_type,
+ ctx->seq, KG_USAGE_SIGN,
+ &plaind, &md5cksum);
+ xfree(data_ptr);
- plain.data = ptr;
+ if (code) {
+ if (toktype == KG_TOK_SEAL_MSG)
+ xfree(token.value);
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
- tseqnum = ((ptr[0]<<24) | (ptr[1]<<16) | (ptr[2]<<8) | ptr[3]);
- ptr += 4;
- tdirection = ptr[0];
- ptr += 1;
+ if ((code = kg_encrypt(context, ctx->seq, KG_USAGE_SEAL,
+ (g_OID_equal(ctx->mech_used, gss_mech_krb5_old) ?
+ ctx->seq->contents : NULL),
+ md5cksum.contents, md5cksum.contents, 16))) {
+ xfree(md5cksum.contents);
+ if (toktype == KG_TOK_SEAL_MSG)
+ xfree(token.value);
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
- tmsglen = (ptr[0]<<8) | ptr[1];
- ptr += 2;
- bodysize -= 11;
+ if (signalg == 0)
+ cksum.length = 8;
+ else
+ cksum.length = 16;
+ cksum.contents = md5cksum.contents + 16 - cksum.length;
- if (bodysize < tmsglen) {
- *minor_status = G_TOK_TRUNC;
- return(GSS_S_DEFECTIVE_TOKEN);
- }
+ code = memcmp(cksum.contents, ptr+14, cksum.length);
+ break;
- tmsg = ptr;
- ptr += tmsglen;
- bodysize -= tmsglen;
+ case SGN_ALG_MD2_5:
+ if (!ctx->seed_init &&
+ (code = kg_make_seed(context, ctx->subkey, ctx->seed))) {
+ xfree(md5cksum.contents);
+ if (sealalg != 0xffff)
+ xfree(plain);
+ if (toktype == KG_TOK_SEAL_MSG)
+ xfree(token.value);
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
- plain.length = ((char*)ptr) - ((char *)plain.data);
+ if (! (data_ptr = (void *)
+ xmalloc(sizeof(ctx->seed) + 8 +
+ (ctx->big_endian ? token.length : plainlen)))) {
+ xfree(md5cksum.contents);
+ if (sealalg == 0)
+ xfree(plain);
+ if (toktype == KG_TOK_SEAL_MSG)
+ xfree(token.value);
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+ (void) memcpy(data_ptr, ptr-2, 8);
+ (void) memcpy(data_ptr+8, ctx->seed, sizeof(ctx->seed));
+ if (ctx->big_endian)
+ (void) memcpy(data_ptr+8+sizeof(ctx->seed),
+ token.value, token.length);
+ else
+ (void) memcpy(data_ptr+8+sizeof(ctx->seed),
+ plain, plainlen);
+ 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,
+ ctx->seq, KG_USAGE_SIGN,
+ &plaind, &md5cksum);
+ xfree(data_ptr);
+
+ if (code) {
+ if (sealalg == 0)
+ xfree(plain);
+ if (toktype == KG_TOK_SEAL_MSG)
+ xfree(token.value);
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
- tcksum.length = (ptr[0]<<8) | ptr[1];
- ptr += 2;
- bodysize -= 2;
+ code = memcmp(md5cksum.contents, ptr+14, 8);
+ /* Falls through to defective-token?? */
- if (bodysize != tcksum.length) {
- *minor_status = G_TOK_TRUNC;
+ default:
+ *minor_status = 0;
return(GSS_S_DEFECTIVE_TOKEN);
- }
- tcksum.contents = ptr;
+ case SGN_ALG_HMAC_SHA1_DES3_KD:
+ /* compute the checksum of the message */
- /* verify the MIC */
+ /* 8 = bytes of token body to be checksummed according to spec */
- 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);
- }
+ if (! (data_ptr = (void *)
+ xmalloc(8 + (ctx->big_endian ? token.length : plainlen)))) {
+ if (sealalg != 0xffff)
+ xfree(plain);
+ if (toktype == KG_TOK_SEAL_MSG)
+ xfree(token.value);
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
- /* 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 (tmsglen) {
- 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);
-}
+ (void) memcpy(data_ptr, ptr-2, 8);
-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;
+ if (ctx->big_endian)
+ (void) memcpy(data_ptr+8, token.value, token.length);
+ else
+ (void) memcpy(data_ptr+8, plain, plainlen);
- output->length = 0;
- output->value = NULL;
+ plaind.length = 8 + (ctx->big_endian ? token.length : plainlen);
+ plaind.data = data_ptr;
+ code = krb5_c_make_checksum(context, md5cksum.checksum_type,
+ ctx->seq, KG_USAGE_SIGN,
+ &plaind, &md5cksum);
+ xfree(data_ptr);
- /* read the body parts out of the message */
+ if (code) {
+ if (toktype == KG_TOK_SEAL_MSG)
+ xfree(token.value);
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
- if (bodysize < 2) {
- *minor_status = G_TOK_TRUNC;
- return(GSS_S_DEFECTIVE_TOKEN);
+ code = memcmp(md5cksum.contents, ptr+14, md5cksum.length);
+ break;
}
- 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);
- }
+ xfree(md5cksum.contents);
+ if (sealalg != 0xffff)
+ xfree(plain);
- cipher.ciphertext.data = ptr;
- cipher.enctype = ENCTYPE_UNKNOWN;
+ /* compare the computed checksum against the transmitted checksum */
- plain.length = cipher.ciphertext.length;
- if ((plain.data = (char *) malloc(plain.length)) == NULL) {
+ if (code) {
+ if (toktype == KG_TOK_SEAL_MSG)
+ xfree(token.value);
*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);
+ return(GSS_S_BAD_SIG);
}
- /* parse out the encrypted fields */
- ptr = plain.data;
- bodysize = plain.length;
+ /* it got through unscathed. Make sure the context is unexpired */
- 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;
+ if (toktype == KG_TOK_SEAL_MSG)
+ *message_buffer = token;
- tmsglen = (ptr[0]<<8) | ptr[1];
- ptr += 2;
- bodysize -= 7;
+ if (conf_state)
+ *conf_state = (sealalg != 0xffff);
- /* check context expiry */
+ if (qop_state)
+ *qop_state = GSS_C_QOP_DEFAULT;
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;
+ if ((code = kg_get_seq_num(context, ctx->seq, ptr+14, ptr+6, &direction,
+ &seqnum))) {
+ if (toktype == KG_TOK_SEAL_MSG)
+ xfree(token.value);
+ *minor_status = code;
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 (tmsglen) {
- 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 ((ctx->initiate && direction != 0xff) ||
+ (!ctx->initiate && direction != 0)) {
+ if (toktype == KG_TOK_SEAL_MSG)
+ xfree(token.value);
+ *minor_status = G_BAD_DIRECTION;
+ return(GSS_S_BAD_SIG);
}
- if (qop_state)
- *qop_state = GSS_C_QOP_DEFAULT;
+ retval = g_order_check(&(ctx->seqstate), seqnum);
- free(plain.data);
+ /* success or ordering violation */
*minor_status = 0;
- return(GSS_S_COMPLETE);
+ 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_v1(context, minor_status, ctx, ptr, bodysize, message_buffer,
- conf_state, qop_state, toktype)
- krb5_context context;
- 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;
+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_error_code code;
- int tmsglen;
- int conflen = 0;
- int signalg;
- int sealalg;
- gss_buffer_desc token;
- krb5_checksum cksum;
- krb5_checksum desmac;
- krb5_checksum md5cksum;
- krb5_data plaind;
- char *data_ptr;
- krb5_timestamp now;
- unsigned char *plain;
- int cksum_len = 0;
- int plainlen;
- int err;
- 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;
- }
-
- /* get the sign and seal algorithms */
-
- signalg = ptr[0] + (ptr[1]<<8);
- sealalg = ptr[2] + (ptr[3]<<8);
-
- /* Sanity checks */
-
- if ((ptr[4] != 0xff) || (ptr[5] != 0xff)) {
- *minor_status = 0;
- return GSS_S_DEFECTIVE_TOKEN;
- }
-
- if ((toktype != KG_TOK_SEAL_MSG) &&
- (sealalg != 0xffff)) {
- *minor_status = 0;
- return GSS_S_DEFECTIVE_TOKEN;
- }
-
- /* in the current spec, there is only one valid seal algorithm per
- key type, so a simple comparison is ok */
-
- if ((toktype == KG_TOK_SEAL_MSG) &&
- !((sealalg == 0xffff) ||
- (sealalg == ctx->sealalg))) {
- *minor_status = 0;
- return GSS_S_DEFECTIVE_TOKEN;
- }
-
- /* there are several mappings of seal algorithms to sign algorithms,
- but few enough that we can try them all. */
-
- if (((ctx->sealalg == 0) &&
- (signalg > 1)) ||
- ((ctx->sealalg == 1) &&
- (signalg != 3))) {
- *minor_status = 0;
- return GSS_S_DEFECTIVE_TOKEN;
- }
-
- switch (signalg) {
- case 0:
- case 1:
- cksum_len = 8;
- break;
- case 3:
- cksum_len = 16;
- break;
- }
-
- if (toktype == KG_TOK_SEAL_MSG)
- tmsglen = bodysize-(14+cksum_len);
-
- /* get the token parameters */
-
- /* decode the message, if SEAL */
-
- if (toktype == KG_TOK_SEAL_MSG) {
- if (sealalg != 0xffff) {
- if ((plain = (unsigned char *) xmalloc(tmsglen)) == NULL) {
- *minor_status = ENOMEM;
- return(GSS_S_FAILURE);
- }
+ krb5_gss_ctx_id_rec *ctx;
+ unsigned char *ptr;
+ int bodysize;
+ int err;
+
+ /* validate the context handle */
+ if (! kg_validate_ctx_id(context_handle)) {
+ *minor_status = (OM_uint32) G_VALIDATE_FAILED;
+ return(GSS_S_NO_CONTEXT);
+ }
- if ((code = kg_decrypt(context, ctx->enc, NULL,
- ptr+14+cksum_len, plain, tmsglen))) {
- xfree(plain);
- *minor_status = code;
- return(GSS_S_FAILURE);
- }
- } else {
- plain = ptr+14+cksum_len;
- }
-
- plainlen = tmsglen;
-
- if ((sealalg == 0xffff) && ctx->big_endian) {
- token.length = tmsglen;
- } else {
- conflen = kg_confounder_size(context, ctx->enc);
- token.length = tmsglen - conflen - plain[tmsglen-1];
- }
-
- if (token.length) {
- if ((token.value = (void *) xmalloc(token.length)) == NULL) {
- if (sealalg != 0xffff)
- xfree(plain);
- *minor_status = ENOMEM;
- return(GSS_S_FAILURE);
- }
- memcpy(token.value, plain+conflen, token.length);
- }
- } else if (toktype == KG_TOK_SIGN_MSG) {
- token = *message_buffer;
- plain = token.value;
- plainlen = token.length;
- } else {
- token.length = 0;
- token.value = NULL;
- plain = token.value;
- plainlen = token.length;
- }
-
- /* compute the checksum of the message */
-
- /* 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 = sumlen;
-
- switch (signalg) {
- case 0:
- case 3:
- /* compute the checksum of the message */
-
- /* 8 = bytes of token body to be checksummed according to spec */
-
- if (! (data_ptr = (void *)
- xmalloc(8 + (ctx->big_endian ? token.length : plainlen)))) {
- if (sealalg != 0xffff)
- xfree(plain);
- if (toktype == KG_TOK_SEAL_MSG)
- xfree(token.value);
- *minor_status = ENOMEM;
- return(GSS_S_FAILURE);
- }
-
- (void) memcpy(data_ptr, ptr-2, 8);
-
- if (ctx->big_endian)
- (void) memcpy(data_ptr+8, token.value, token.length);
- else
- (void) memcpy(data_ptr+8, plain, plainlen);
-
- 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) {
- if (toktype == KG_TOK_SEAL_MSG)
- xfree(token.value);
- *minor_status = code;
- return(GSS_S_FAILURE);
- }
-
-#if 0
- /* XXX this depends on the key being a single-des key, but that's
- all that kerberos supports right now */
-
- /* 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) {
- xfree(md5cksum.contents);
- if (toktype == KG_TOK_SEAL_MSG)
- xfree(token.value);
- *minor_status = ENOMEM;
- 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,
- ctx->seq.key->length,
- &cksum)) {
- xfree(cksum.contents);
- xfree(md5cksum.contents);
- if (toktype == KG_TOK_SEAL_MSG)
- xfree(token.value);
- *minor_status = code;
- return(GSS_S_FAILURE);
- }
-
- code = memcmp(cksum.contents, ptr+14, cksum.length);
-
- xfree(cksum.contents);
-#else
- if ((code = kg_encrypt(context, ctx->seq,
- (g_OID_equal(ctx->mech_used, gss_mech_krb5_old) ?
- ctx->seq->contents : NULL),
- md5cksum.contents, md5cksum.contents, 16))) {
- xfree(md5cksum.contents);
- if (toktype == KG_TOK_SEAL_MSG)
- xfree(token.value);
- *minor_status = code;
- return GSS_S_FAILURE;
- }
+ ctx = (krb5_gss_ctx_id_rec *) context_handle;
- if (signalg == 0)
- cksum.length = 8;
- else
- cksum.length = 16;
- cksum.contents = md5cksum.contents + 16 - cksum.length;
+ if (! ctx->established) {
+ *minor_status = KG_CTX_INCOMPLETE;
+ return(GSS_S_NO_CONTEXT);
+ }
- code = memcmp(cksum.contents, ptr+14, cksum.length);
-#endif
- break;
-
- case 1:
- if (!ctx->seed_init &&
- (code = kg_make_seed(context, ctx->subkey, ctx->seed))) {
- xfree(md5cksum.contents);
- if (sealalg != 0xffff)
- xfree(plain);
- if (toktype == KG_TOK_SEAL_MSG)
- xfree(token.value);
- *minor_status = code;
- return GSS_S_FAILURE;
- }
-
- if (! (data_ptr = (void *)
- xmalloc(sizeof(ctx->seed) + 8 +
- (ctx->big_endian ? token.length : plainlen)))) {
- xfree(md5cksum.contents);
- if (sealalg == 0)
- xfree(plain);
- if (toktype == KG_TOK_SEAL_MSG)
- xfree(token.value);
- *minor_status = ENOMEM;
- return(GSS_S_FAILURE);
- }
- (void) memcpy(data_ptr, ptr-2, 8);
- (void) memcpy(data_ptr+8, ctx->seed, sizeof(ctx->seed));
- if (ctx->big_endian)
- (void) memcpy(data_ptr+8+sizeof(ctx->seed),
- token.value, token.length);
- else
- (void) memcpy(data_ptr+8+sizeof(ctx->seed),
- plain, plainlen);
- 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) {
- if (sealalg == 0)
- xfree(plain);
- if (toktype == KG_TOK_SEAL_MSG)
- xfree(token.value);
- *minor_status = code;
- return(GSS_S_FAILURE);
- }
-
- code = memcmp(md5cksum.contents, ptr+14, 8);
-
- default:
- *minor_status = 0;
- return(GSS_S_DEFECTIVE_TOKEN);
- }
-
- xfree(md5cksum.contents);
- if (sealalg != 0xffff)
- xfree(plain);
-
- /* compare the computed checksum against the transmitted checksum */
-
- if (code) {
- if (toktype == KG_TOK_SEAL_MSG)
- xfree(token.value);
- *minor_status = 0;
- return(GSS_S_BAD_SIG);
- }
-
-
- /* it got through unscathed. Make sure the context is unexpired */
-
- if (toktype == KG_TOK_SEAL_MSG)
- *message_buffer = token;
-
- if (conf_state)
- *conf_state = (sealalg != 0xffff);
-
- if (qop_state)
- *qop_state = GSS_C_QOP_DEFAULT;
-
- 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 ((code = kg_get_seq_num(context, ctx->seq, ptr+14, ptr+6, &direction,
- &seqnum))) {
- if (toktype == KG_TOK_SEAL_MSG)
- xfree(token.value);
- *minor_status = code;
- return(GSS_S_BAD_SIG);
- }
-
- if ((ctx->initiate && direction != 0xff) ||
- (!ctx->initiate && direction != 0)) {
- if (toktype == KG_TOK_SEAL_MSG)
- xfree(token.value);
- *minor_status = G_BAD_DIRECTION;
- return(GSS_S_BAD_SIG);
- }
-
- retval = g_order_check(&(ctx->seqstate), seqnum);
-
- /* success or ordering violation */
-
- *minor_status = 0;
- return(retval);
-}
+ /* parse the token, leave the data in message_buffer, setting conf_state */
-/* message_buffer is an input if SIGN, output if SEAL, and ignored if DEL_CTX
- conf_state is only valid if SEAL. */
+ /* verify the header */
-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);
+ 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));
+ }
+
+ *minor_status = err;
+ return(GSS_S_DEFECTIVE_TOKEN);
}