2 * Copyright 1993 by OpenVision Technologies, Inc.
4 * Permission to use, copy, modify, distribute, and sell this software
5 * and its documentation for any purpose is hereby granted without fee,
6 * provided that the above copyright notice appears in all copies and
7 * that both that copyright notice and this permission notice appear in
8 * supporting documentation, and that the name of OpenVision not be used
9 * in advertising or publicity pertaining to distribution of the software
10 * without specific, written prior permission. OpenVision makes no
11 * representations about the suitability of this software for any
12 * purpose. It is provided "as is" without express or implied warranty.
14 * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
18 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
19 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
23 #include "gssapiP_krb5.h"
25 #include <krb5/rsa-md5.h>
27 /* message_buffer is an input if SIGN, output if SEAL, and ignored if DEL_CTX
28 conf_state is only valid if SEAL.
32 kg_unseal(minor_status, context_handle, input_token_buffer, message_buffer,
33 conf_state, qop_state, toktype)
34 OM_uint32 *minor_status;
35 gss_ctx_id_t context_handle;
36 gss_buffer_t input_token_buffer;
37 gss_buffer_t message_buffer;
42 krb5_gss_ctx_id_rec *ctx;
48 gss_buffer_desc token;
57 if (toktype == KG_TOK_SEAL_MSG) {
58 message_buffer->length = 0;
59 message_buffer->value = NULL;
62 /* validate the context handle */
63 if (! kg_validate_ctx_id(context_handle)) {
64 *minor_status = (OM_uint32) G_VALIDATE_FAILED;
65 return(GSS_S_NO_CONTEXT);
68 ctx = (krb5_gss_ctx_id_rec *) context_handle;
70 if (! ctx->established) {
71 *minor_status = KG_CTX_INCOMPLETE;
72 return(GSS_S_NO_CONTEXT);
75 /* parse the token, leave the data in message_buffer, setting conf_state */
77 /* verify the header */
79 ptr = (unsigned char *) input_token_buffer->value;
81 if (! g_verify_token_header(gss_mech_krb5, &bodysize,
82 &ptr, toktype, input_token_buffer->length)) {
84 return(GSS_S_DEFECTIVE_TOKEN);
87 if (toktype == KG_TOK_SEAL_MSG)
88 tmsglen = bodysize-22;
90 /* get the sign and seal algorithms */
92 signalg = ptr[0] + (ptr[1]<<8);
93 sealalg = ptr[2] + (ptr[3]<<8);
95 if (((signalg != 0) && (signalg != 1)) ||
96 ((toktype != KG_TOK_SEAL_MSG) && (sealalg != 0xffff)) ||
97 ((toktype == KG_TOK_SEAL_MSG) &&
98 ((sealalg != 0xffff) && (sealalg != 0))) ||
102 return(GSS_S_DEFECTIVE_TOKEN);
105 /* get the token parameters */
107 /* decode the message, if SEAL */
109 if (toktype == KG_TOK_SEAL_MSG) {
111 if ((plain = (unsigned char *) xmalloc(tmsglen)) == NULL) {
112 *minor_status = ENOMEM;
113 return(GSS_S_FAILURE);
116 if (code = kg_decrypt(&ctx->enc, NULL, ptr+22, plain, tmsglen)) {
118 *minor_status = code;
119 return(GSS_S_FAILURE);
127 if (sealalg && ctx->big_endian)
128 token.length = tmsglen;
130 token.length = tmsglen - 8 - plain[tmsglen-1];
133 if ((token.value = xmalloc(token.length)) == NULL) {
136 *minor_status = ENOMEM;
137 return(GSS_S_FAILURE);
140 if (sealalg && ctx->big_endian)
141 memcpy(token.value, plain, token.length);
143 memcpy(token.value, plain+8, token.length);
145 } else if (toktype == KG_TOK_SIGN_MSG) {
146 token = *message_buffer;
148 plainlen = token.length;
153 plainlen = token.length;
156 /* compute the checksum of the message */
159 /* compute the checksum of the message */
162 MD5Update(&md5, (unsigned char *) ptr-2, 8);
164 MD5Update(&md5, token.value, token.length);
166 MD5Update(&md5, plain, plainlen);
172 /* XXX this depends on the key being a single-des key, but that's
173 all that kerberos supports right now */
175 if (code = krb5_calculate_checksum(context, CKSUMTYPE_DESCBC, md5.digest,
176 16, ctx->seq.key->contents,
177 ctx->seq.key->length,
179 if (toktype == KG_TOK_SEAL_MSG)
181 *minor_status = code;
182 return(GSS_S_FAILURE);
185 cksum = desmac.contents;
187 if (! ctx->seed_init) {
188 if (code = kg_make_seed(ctx->subkey, ctx->seed)) {
191 if (toktype == KG_TOK_SEAL_MSG)
193 *minor_status = code;
194 return(GSS_S_FAILURE);
200 MD5Update(&md5, ctx->seed, sizeof(ctx->seed));
201 MD5Update(&md5, (unsigned char *) ptr-2, 8);
203 MD5Update(&md5, token.value, token.length);
205 MD5Update(&md5, plain, plainlen);
214 /* compare the computed checksum against the transmitted checksum */
216 if (memcmp(cksum, ptr+14, 8) != 0) {
218 xfree(desmac.contents);
219 if (toktype == KG_TOK_SEAL_MSG)
222 return(GSS_S_BAD_SIG);
226 xfree(desmac.contents);
228 /* XXX this is where the seq_num check would go */
230 /* it got through unscathed. Make sure the context is unexpired */
232 if (toktype == KG_TOK_SEAL_MSG)
233 *message_buffer = token;
236 *conf_state = (sealalg == 0);
239 *qop_state = GSS_C_QOP_DEFAULT;
241 if (code = krb5_timeofday(ctx->context, &now)) {
242 *minor_status = code;
243 return(GSS_S_FAILURE);
246 if (now > ctx->endtime) {
248 return(GSS_S_CONTEXT_EXPIRED);
254 return(GSS_S_COMPLETE);