1 /*
2 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
3 */
4 /*
5 * Copyright 1993 by OpenVision Technologies, Inc.
6 *
7 * Permission to use, copy, modify, distribute, and sell this software
8 * and its documentation for any purpose is hereby granted without fee,
9 * provided that the above copyright notice appears in all copies and
10 * that both that copyright notice and this permission notice appear in
11 * supporting documentation, and that the name of OpenVision not be used
12 * in advertising or publicity pertaining to distribution of the software
13 * without specific, written prior permission. OpenVision makes no
14 * representations about the suitability of this software for any
15 * purpose. It is provided "as is" without express or implied warranty.
16 *
17 * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
18 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
19 * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
20 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
21 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
22 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
23 * PERFORMANCE OF THIS SOFTWARE.
24 */
25
26 /*
27 * Copyright (C) 1998 by the FundsXpress, INC.
28 *
29 * All rights reserved.
30 *
31 * Export of this software from the United States of America may require
32 * a specific license from the United States Government. It is the
33 * responsibility of any person or organization contemplating export to
34 * obtain such a license before exporting.
35 *
36 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
37 * distribute this software and its documentation for any purpose and
38 * without fee is hereby granted, provided that the above copyright
39 * notice appear in all copies and that both that copyright notice and
40 * this permission notice appear in supporting documentation, and that
41 * the name of FundsXpress. not be used in advertising or publicity pertaining
42 * to distribution of the software without specific, written prior
43 * permission. FundsXpress makes no representations about the suitability of
44 * this software for any purpose. It is provided "as is" without express
45 * or implied warranty.
46 *
47 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
48 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
49 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
50 */
51
52 #include "gssapiP_krb5.h"
53 #include <k5-int.h>
54
55 static krb5_error_code
make_seal_token_v1(krb5_context context,krb5_keyblock * enc,krb5_keyblock * seq,gssint_uint64 * seqnum,int direction,gss_buffer_t text,gss_buffer_t token,int signalg,size_t cksum_size,int sealalg,int encrypt,int toktype,int bigend,gss_OID oid)56 make_seal_token_v1 (krb5_context context,
57 krb5_keyblock *enc,
58 krb5_keyblock *seq,
59 gssint_uint64 *seqnum,
60 int direction,
61 gss_buffer_t text,
62 gss_buffer_t token,
63 int signalg,
64 size_t cksum_size,
65 int sealalg,
66 int encrypt,
67 int toktype,
68 int bigend,
69 gss_OID oid)
70 {
71 krb5_error_code code;
72 size_t sumlen;
73 char *data_ptr;
74 krb5_data plaind;
75 krb5_checksum md5cksum;
76 krb5_checksum cksum;
77 /* msglen contains the message length
78 * we are signing/encrypting. tmsglen
79 * contains the length of the message
80 * we plan to write out to the token.
81 * tlen is the length of the token
82 * including header. */
83 unsigned conflen=0, tmsglen, tlen, msglen;
84 unsigned char *t, *ptr;
85 unsigned char *plain;
86 unsigned char pad;
87 krb5_keyusage sign_usage = KG_USAGE_SIGN;
88 OM_uint32 seqnum32;
89
90 /* Solaris Kerberos: check for recognized signalg and sealalg */
91 KRB5_LOG0(KRB5_INFO, "make_seal_token_v1() start\n");
92 #ifdef _KERNEL
93 /*
94 * Because the ARCFOUR code bypasses the standard
95 * crypto interfaces, we must make sure the kernel
96 * crypto framework mechanism types are properly
97 * initialized here.
98 */
99 context->kef_cipher_mt = get_cipher_mech_type(context, seq);
100 context->kef_hash_mt = get_hash_mech_type(context, seq);
101 if ((code = init_key_kef(context->kef_cipher_mt, seq))) {
102 return (code);
103 }
104 if ((code = init_key_kef(context->kef_cipher_mt, enc))) {
105 return (code);
106 }
107 #endif /* _KERNEL */
108
109 /* create the token buffer */
110 /* Do we need confounder? */
111 if (encrypt || (!bigend && (toktype == KG_TOK_SEAL_MSG)))
112 conflen = kg_confounder_size(context, enc);
113 else conflen = 0;
114
115 if (toktype == KG_TOK_SEAL_MSG) {
116 switch (sealalg) {
117 case SEAL_ALG_MICROSOFT_RC4:
118 msglen = conflen + text->length+1;
119 pad = 1;
120 break;
121 default:
122 /* XXX knows that des block size is 8 */
123 msglen = (conflen+text->length+8)&(~7);
124 pad = 8-(text->length%8);
125 }
126 tmsglen = msglen;
127 } else {
128 tmsglen = 0;
129 msglen = text->length;
130 pad = 0;
131 }
132 tlen = g_token_size((gss_OID) oid, 14+cksum_size+tmsglen);
133
134 if ((t = (unsigned char *) xmalloc(tlen)) == NULL)
135 return(ENOMEM);
136
137 /*** fill in the token */
138
139 ptr = t;
140 g_make_token_header((gss_OID) oid, 14+cksum_size+tmsglen, &ptr, toktype);
141
142 /* 0..1 SIGN_ALG */
143 ptr[0] = (unsigned char) (signalg & 0xff);
144 ptr[1] = (unsigned char) ((signalg >> 8) & 0xff);
145
146 /* 2..3 SEAL_ALG or Filler */
147 if ((toktype == KG_TOK_SEAL_MSG) && encrypt) {
148 ptr[2] = (unsigned char) (sealalg & 0xff);
149 ptr[3] = (unsigned char) ((sealalg >> 8) & 0xff);
150 } else {
151 /* No seal */
152 ptr[2] = 0xff;
153 ptr[3] = 0xff;
154 }
155
156 /* 4..5 Filler */
157 ptr[4] = 0xff;
158 ptr[5] = 0xff;
159
160 /* pad the plaintext, encrypt if needed, and stick it in the token */
161
162 /* initialize the the cksum */
163 switch (signalg) {
164 case SGN_ALG_DES_MAC_MD5:
165 case SGN_ALG_MD2_5:
166 md5cksum.checksum_type = CKSUMTYPE_RSA_MD5;
167 break;
168 case SGN_ALG_HMAC_SHA1_DES3_KD:
169 md5cksum.checksum_type = CKSUMTYPE_HMAC_SHA1_DES3;
170 break;
171 case SGN_ALG_HMAC_MD5:
172 md5cksum.checksum_type = CKSUMTYPE_HMAC_MD5_ARCFOUR;
173 if (toktype != KG_TOK_SEAL_MSG)
174 sign_usage = 15;
175 break;
176 default:
177 KRB5_LOG(KRB5_ERR, "make_seal_token_v1() end, error2 signalg=%d\n",
178 signalg);
179 #ifndef _KERNEL
180 abort ();
181 #else
182 return (GSS_S_DEFECTIVE_TOKEN);
183 #endif /* _KERNEL */
184 }
185
186 code = krb5_c_checksum_length(context, md5cksum.checksum_type, &sumlen);
187 if (code) {
188 KRB5_LOG(KRB5_ERR, "make_seal_token_v1() end, krb5_c_checksum_length() "
189 "error code=%d\n", code);
190 return(code);
191 }
192 md5cksum.length = sumlen;
193
194
195 if ((plain = (unsigned char *) xmalloc(msglen ? msglen : 1)) == NULL) {
196 xfree_wrap(t, tlen);
197 return(ENOMEM);
198 }
199
200 if (conflen) {
201 if ((code = kg_make_confounder(context, enc, plain))) {
202 xfree_wrap(plain, msglen ? msglen : 1);
203 xfree_wrap(t, tlen);
204 KRB5_LOG(KRB5_ERR, "make_seal_token_v1() end, "
205 "kg_make_confounder() error code=%d\n", code);
206 return(code);
207 }
208 }
209
210 (void) memcpy(plain+conflen, text->value, text->length);
211 if (pad) (void) memset(plain+conflen+text->length, pad, pad);
212
213 /* compute the checksum */
214
215 /* 8 = head of token body as specified by mech spec */
216 if (! (data_ptr = (char *) xmalloc(8 +
217 (bigend ? text->length : msglen)))) {
218 xfree_wrap(plain, msglen ? msglen : 1);
219 xfree_wrap(t, tlen);
220 return(ENOMEM);
221 }
222 (void) memcpy(data_ptr, ptr-2, 8);
223 if (bigend)
224 (void) memcpy(data_ptr+8, text->value, text->length);
225 else
226 (void) memcpy(data_ptr+8, plain, msglen);
227 plaind.length = 8 + (bigend ? text->length : msglen);
228 plaind.data = data_ptr;
229 code = krb5_c_make_checksum(context, md5cksum.checksum_type, seq,
230 sign_usage, &plaind, &md5cksum);
231 xfree_wrap(data_ptr,8 + (bigend ? text->length : msglen));
232
233 if (code) {
234 KRB5_LOG(KRB5_ERR, "make_seal_token_v1() end, "
235 "krb5_c_make_checksum() error code=%d\n", code);
236 xfree_wrap(plain, msglen ? msglen : 1);
237 xfree_wrap(t, tlen);
238 return(code);
239 }
240 switch(signalg) {
241 case SGN_ALG_DES_MAC_MD5:
242 case 3:
243
244 if ((code = kg_encrypt(context, seq, KG_USAGE_SEAL,
245 (g_OID_equal(oid, gss_mech_krb5_old) ?
246 seq->contents : NULL),
247 md5cksum.contents, md5cksum.contents, 16))) {
248 xfree_wrap(md5cksum.contents, md5cksum.length);
249 xfree_wrap(t, tlen);
250
251 KRB5_LOG(KRB5_ERR, "make_seal_token_v1() end, kg_encrypt() "
252 "error code=%d\n", code);
253 return code;
254 }
255
256 cksum.length = cksum_size;
257 cksum.contents = md5cksum.contents + 16 - cksum.length;
258
259 (void) memcpy(ptr+14, cksum.contents, cksum.length);
260 break;
261
262 case SGN_ALG_HMAC_SHA1_DES3_KD:
263 /*
264 * Using key derivation, the call to krb5_c_make_checksum
265 * already dealt with encrypting.
266 */
267 if (md5cksum.length != cksum_size)
268 {
269 KRB5_LOG1(KRB5_ERR, "make_seal_token_v1() end, error "
270 "md5cksum.length %u != "
271 "cksum_size %u\n",
272 (unsigned int)md5cksum.length,
273 (unsigned int) cksum_size);
274 #ifndef _KERNEL
275 abort ();
276 #else
277 return (GSS_S_DEFECTIVE_TOKEN);
278 #endif
279 }
280 (void) memcpy(ptr+14, md5cksum.contents, md5cksum.length);
281 break;
282 case SGN_ALG_HMAC_MD5:
283 KRB5_LOG(KRB5_INFO, "make_seal_token_v1() cksum_size = %u",
284 (unsigned int)cksum_size);
285 (void) memcpy(ptr+14, md5cksum.contents, cksum_size);
286 break;
287 }
288
289 xfree_wrap(md5cksum.contents, md5cksum.length);
290
291 /* create the seq_num */
292 seqnum32 = (OM_uint32)(*seqnum & 0xFFFFFFFF);
293 if ((code = kg_make_seq_num(context, seq, direction?0:0xff, seqnum32,
294 ptr+14, ptr+6))) {
295 xfree_wrap(t, tlen);
296
297 KRB5_LOG(KRB5_ERR, "make_seal_token_v1() end, kg_make_seq_num() "
298 "error code=%d\n", code);
299 return(code);
300 }
301
302 if (encrypt) {
303 switch(sealalg) {
304 case SEAL_ALG_MICROSOFT_RC4:
305 {
306 unsigned char bigend_seqnum[4];
307 krb5_keyblock *enc_key;
308 int i;
309 bigend_seqnum[0] = (*seqnum>>24) & 0xff;
310 bigend_seqnum[1] = (*seqnum>>16) & 0xff;
311 bigend_seqnum[2] = (*seqnum>>8) & 0xff;
312 bigend_seqnum[3] = *seqnum & 0xff;
313 code = krb5_copy_keyblock (context, enc, &enc_key);
314 if (code)
315 {
316 xfree_wrap(plain, msglen ? msglen : 1);
317 xfree_wrap(t, tlen);
318 return(code);
319 }
320 for (i = 0; i <= 15; i++)
321 ((char *) enc_key->contents)[i] ^=0xf0;
322 code = kg_arcfour_docrypt (context, enc_key, 0,
323 bigend_seqnum, 4,
324 plain, tmsglen,
325 ptr+14+cksum_size);
326 krb5_free_keyblock (context, enc_key);
327 if (code)
328 {
329 xfree_wrap(plain, msglen ? msglen : 1);
330 xfree_wrap(t, tlen);
331 return(code);
332 }
333 }
334 break;
335 default:
336 if ((code = kg_encrypt(context, enc, KG_USAGE_SEAL, NULL,
337 (krb5_pointer) plain,
338 (krb5_pointer) (ptr+cksum_size+14),
339 tmsglen))) {
340 xfree_wrap(plain, msglen ? msglen : 1);
341 xfree_wrap(t, tlen);
342 return(code);
343 }
344 }
345 }else {
346 if (tmsglen)
347 (void) memcpy(ptr+14+cksum_size, plain, tmsglen);
348 }
349 xfree_wrap(plain, msglen ? msglen : 1);
350
351
352 /* that's it. return the token */
353
354 (*seqnum)++;
355 *seqnum &= (ulong_t)0xffffffffU;
356
357 token->length = tlen;
358 token->value = (void *) t;
359
360 KRB5_LOG0(KRB5_INFO, "make_seal_token_v1() end\n");
361 return(0);
362 }
363
364 /* if signonly is true, ignore conf_req, conf_state,
365 and do not encode the ENC_TYPE, MSG_LENGTH, or MSG_TEXT fields */
366
367 OM_uint32
kg_seal(minor_status,context_handle,conf_req_flag,qop_req,input_message_buffer,conf_state,output_message_buffer,toktype)368 kg_seal(minor_status, context_handle, conf_req_flag, qop_req,
369 input_message_buffer, conf_state, output_message_buffer, toktype)
370 OM_uint32 *minor_status;
371 gss_ctx_id_t context_handle;
372 int conf_req_flag;
373 int qop_req;
374 gss_buffer_t input_message_buffer;
375 int *conf_state;
376 gss_buffer_t output_message_buffer;
377 int toktype;
378 {
379 krb5_gss_ctx_id_rec *ctx;
380 krb5_error_code code;
381 krb5_timestamp now;
382 krb5_context context;
383
384 KRB5_LOG0(KRB5_INFO, "kg_seal() start");
385
386 output_message_buffer->length = 0;
387 output_message_buffer->value = NULL;
388
389 /* Only default qop or matching established cryptosystem is allowed.
390
391 There are NO EXTENSIONS to this set for AES and friends! The
392 new spec says "just use 0". The old spec plus extensions would
393 actually allow for certain non-zero values. Fix this to handle
394 them later. */
395 if (qop_req != 0) {
396 *minor_status = (OM_uint32) G_UNKNOWN_QOP;
397 KRB5_LOG0(KRB5_ERR, "kg_seal() end, error G_UNKNOWN_QOP\n");
398 return (GSS_S_BAD_QOP);
399 }
400
401 /* validate the context handle */
402 if (! kg_validate_ctx_id(context_handle)) {
403 *minor_status = (OM_uint32) G_VALIDATE_FAILED;
404 KRB5_LOG0(KRB5_ERR, "kg_seal() kg_validate_ctx_id() end, "
405 "error GSS_S_NO_CONTEXT\n");
406 return (GSS_S_NO_CONTEXT);
407 }
408
409 ctx = (krb5_gss_ctx_id_rec *) context_handle;
410
411 if (ctx->subkey == NULL && !ctx->established) {
412 *minor_status = KG_CTX_INCOMPLETE;
413 return(GSS_S_NO_CONTEXT);
414 }
415
416 context = ctx->k5_context;
417 if ((code = krb5_timeofday(context, &now))) {
418 *minor_status = code;
419 save_error_info(*minor_status, context);
420 KRB5_LOG(KRB5_ERR, "kg_seal() end, krb5_timeofday() error code=%d\n", code);
421 return (GSS_S_FAILURE);
422 }
423
424 switch (ctx->proto)
425 {
426 case 0:
427 code = make_seal_token_v1(context, ctx->enc, ctx->seq,
428 &ctx->seq_send, ctx->initiate,
429 input_message_buffer, output_message_buffer,
430 ctx->signalg, ctx->cksum_size, ctx->sealalg,
431 conf_req_flag, toktype, ctx->big_endian,
432 ctx->mech_used);
433 break;
434 case 1:
435 code = gss_krb5int_make_seal_token_v3(context, ctx,
436 input_message_buffer,
437 output_message_buffer,
438 conf_req_flag, toktype);
439 break;
440 default:
441 code = G_UNKNOWN_QOP; /* XXX */
442 break;
443 }
444
445 if (code) {
446 *minor_status = code;
447 save_error_info(*minor_status, context);
448 KRB5_LOG(KRB5_ERR, "kg_seal() end, make_seal_token_v1() "
449 "error code=%d\n", code);
450 return (GSS_S_FAILURE);
451 }
452
453 if (conf_state)
454 *conf_state = conf_req_flag;
455
456 *minor_status = 0;
457 if (ctx->endtime < now) {
458 (void) gss_release_buffer(minor_status, output_message_buffer);
459 KRB5_LOG(KRB5_ERR, "kg_seal() end, error GSS_S_CONTEXT_EXPIRED "
460 "ctx->endtime = %d\n", ctx->endtime);
461 return (GSS_S_CONTEXT_EXPIRED);
462 }
463
464 KRB5_LOG0(KRB5_INFO, "kg_seal() end\n");
465 return (GSS_S_COMPLETE);
466 }
467