1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3 * Copyright 1993 by OpenVision Technologies, Inc.
4 *
5 * Permission to use, copy, modify, distribute, and sell this software
6 * and its documentation for any purpose is hereby granted without fee,
7 * provided that the above copyright notice appears in all copies and
8 * that both that copyright notice and this permission notice appear in
9 * supporting documentation, and that the name of OpenVision not be used
10 * in advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. OpenVision makes no
12 * representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
14 *
15 * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17 * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
19 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
20 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21 * PERFORMANCE OF THIS SOFTWARE.
22 */
23
24 /*
25 * Copyright (C) 1998 by the FundsXpress, INC.
26 *
27 * All rights reserved.
28 *
29 * Export of this software from the United States of America may require
30 * a specific license from the United States Government. It is the
31 * responsibility of any person or organization contemplating export to
32 * obtain such a license before exporting.
33 *
34 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
35 * distribute this software and its documentation for any purpose and
36 * without fee is hereby granted, provided that the above copyright
37 * notice appear in all copies and that both that copyright notice and
38 * this permission notice appear in supporting documentation, and that
39 * the name of FundsXpress. not be used in advertising or publicity pertaining
40 * to distribution of the software without specific, written prior
41 * permission. FundsXpress makes no representations about the suitability of
42 * this software for any purpose. It is provided "as is" without express
43 * or implied warranty.
44 *
45 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
46 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
47 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
48 */
49
50 #include "gssapiP_krb5.h"
51
52 #include <assert.h>
53
54 static krb5_error_code
make_seal_token_v1(krb5_context context,krb5_key enc,krb5_key seq,uint64_t * seqnum,int direction,gss_buffer_t text,gss_buffer_t token,int signalg,size_t cksum_size,int sealalg,int do_encrypt,int toktype,gss_OID oid)55 make_seal_token_v1 (krb5_context context,
56 krb5_key enc,
57 krb5_key seq,
58 uint64_t *seqnum,
59 int direction,
60 gss_buffer_t text,
61 gss_buffer_t token,
62 int signalg,
63 size_t cksum_size,
64 int sealalg,
65 int do_encrypt,
66 int toktype,
67 gss_OID oid)
68 {
69 krb5_error_code code;
70 size_t sumlen;
71 char *data_ptr;
72 krb5_data plaind;
73 krb5_checksum md5cksum;
74 /* msglen contains the message length
75 * we are signing/encrypting. tmsglen
76 * contains the length of the message
77 * we plan to write out to the token.
78 * tlen is the length of the token
79 * including header. */
80 unsigned int conflen=0, tmsglen, tlen, msglen;
81 unsigned char *t, *metadata, *checksum, *payload;
82 unsigned char *plain;
83 unsigned char pad;
84 krb5_keyusage sign_usage = KG_USAGE_SIGN;
85 struct k5buf buf;
86
87 assert((!do_encrypt) || (toktype == KG_TOK_SEAL_MSG));
88 /* create the token buffer */
89 /* Do we need confounder? */
90 if (do_encrypt || toktype == KG_TOK_SEAL_MSG)
91 conflen = kg_confounder_size(context, enc->keyblock.enctype);
92 else conflen = 0;
93
94 if (toktype == KG_TOK_SEAL_MSG) {
95 switch (sealalg) {
96 case SEAL_ALG_MICROSOFT_RC4:
97 msglen = conflen + text->length+1;
98 pad = 1;
99 break;
100 default:
101 /* XXX knows that des block size is 8 */
102 msglen = (conflen+text->length+8)&(~7);
103 pad = 8-(text->length%8);
104 }
105 tmsglen = msglen;
106 } else {
107 tmsglen = 0;
108 msglen = text->length;
109 pad = 0;
110 }
111
112 tlen = g_token_size(oid, 14 + cksum_size + tmsglen);
113 t = gssalloc_malloc(tlen);
114 if (t == NULL)
115 return(ENOMEM);
116 k5_buf_init_fixed(&buf, t, tlen);
117
118 /*** fill in the token */
119
120 g_make_token_header(&buf, oid, 14 + cksum_size + tmsglen, toktype);
121 metadata = k5_buf_get_space(&buf, 14);
122 checksum = k5_buf_get_space(&buf, cksum_size);
123 payload = k5_buf_get_space(&buf, tmsglen);
124 assert(metadata != NULL && checksum != NULL && payload != NULL);
125 assert(buf.len == tlen);
126
127 /* 0..1 SIGN_ALG */
128 store_16_le(signalg, &metadata[0]);
129
130 /* 2..3 SEAL_ALG or Filler */
131 if ((toktype == KG_TOK_SEAL_MSG) && do_encrypt) {
132 store_16_le(sealalg, &metadata[2]);
133 } else {
134 /* No seal */
135 metadata[2] = 0xFF;
136 metadata[3] = 0xFF;
137 }
138
139 /* 4..5 Filler */
140 metadata[4] = 0xFF;
141 metadata[5] = 0xFF;
142
143 /* pad the plaintext, encrypt if needed, and stick it in the token */
144
145 /* initialize the the checksum */
146 switch (signalg) {
147 case SGN_ALG_HMAC_SHA1_DES3_KD:
148 md5cksum.checksum_type = CKSUMTYPE_HMAC_SHA1_DES3;
149 break;
150 case SGN_ALG_HMAC_MD5:
151 md5cksum.checksum_type = CKSUMTYPE_HMAC_MD5_ARCFOUR;
152 if (toktype != KG_TOK_SEAL_MSG)
153 sign_usage = 15;
154 break;
155 default:
156 abort ();
157 }
158
159 code = krb5_c_checksum_length(context, md5cksum.checksum_type, &sumlen);
160 if (code) {
161 gssalloc_free(t);
162 return(code);
163 }
164 md5cksum.length = sumlen;
165
166
167 if ((plain = (unsigned char *) xmalloc(msglen ? msglen : 1)) == NULL) {
168 gssalloc_free(t);
169 return(ENOMEM);
170 }
171
172 if (conflen) {
173 if ((code = kg_make_confounder(context, enc->keyblock.enctype,
174 plain))) {
175 xfree(plain);
176 gssalloc_free(t);
177 return(code);
178 }
179 }
180
181 memcpy(plain+conflen, text->value, text->length);
182 if (pad) memset(plain+conflen+text->length, pad, pad);
183
184 /* compute the checksum */
185
186 /* 8 = head of token body as specified by mech spec */
187 if (! (data_ptr = xmalloc(8 + msglen))) {
188 xfree(plain);
189 gssalloc_free(t);
190 return(ENOMEM);
191 }
192 /* Checksum over the token ID, metadata bytes, and plaintext. */
193 memcpy(data_ptr, metadata - 2, 8);
194 memcpy(data_ptr + 8, plain, msglen);
195 plaind.length = 8 + msglen;
196 plaind.data = data_ptr;
197 code = krb5_k_make_checksum(context, md5cksum.checksum_type, seq,
198 sign_usage, &plaind, &md5cksum);
199 xfree(data_ptr);
200
201 if (code) {
202 xfree(plain);
203 gssalloc_free(t);
204 return(code);
205 }
206 switch(signalg) {
207 case SGN_ALG_HMAC_SHA1_DES3_KD:
208 /*
209 * Using key derivation, the call to krb5_c_make_checksum
210 * already dealt with encrypting.
211 */
212 if (md5cksum.length != cksum_size)
213 abort ();
214 memcpy(checksum, md5cksum.contents, md5cksum.length);
215 break;
216 case SGN_ALG_HMAC_MD5:
217 memcpy(checksum, md5cksum.contents, cksum_size);
218 break;
219 }
220
221 krb5_free_checksum_contents(context, &md5cksum);
222
223 /* create the seq_num */
224
225 code = kg_make_seq_num(context, seq, direction?0:0xff,
226 (krb5_ui_4)*seqnum, checksum, metadata + 6);
227 if (code) {
228 xfree (plain);
229 gssalloc_free(t);
230 return(code);
231 }
232
233 if (do_encrypt) {
234 switch(sealalg) {
235 case SEAL_ALG_MICROSOFT_RC4:
236 {
237 unsigned char bigend_seqnum[4];
238 krb5_keyblock *enc_key;
239 int i;
240 store_32_be(*seqnum, bigend_seqnum);
241 code = krb5_k_key_keyblock(context, enc, &enc_key);
242 if (code)
243 {
244 xfree(plain);
245 gssalloc_free(t);
246 return(code);
247 }
248 assert (enc_key->length == 16);
249 for (i = 0; i <= 15; i++)
250 ((char *) enc_key->contents)[i] ^=0xf0;
251 code = kg_arcfour_docrypt(enc_key, 0, bigend_seqnum, 4, plain,
252 tmsglen, payload);
253 krb5_free_keyblock (context, enc_key);
254 if (code)
255 {
256 xfree(plain);
257 gssalloc_free(t);
258 return(code);
259 }
260 }
261 break;
262 default:
263 code = kg_encrypt(context, enc, KG_USAGE_SEAL, NULL, plain,
264 payload, tmsglen);
265 if (code) {
266 xfree(plain);
267 gssalloc_free(t);
268 return(code);
269 }
270 }
271 }else {
272 if (tmsglen)
273 memcpy(payload, plain, tmsglen);
274 }
275 xfree(plain);
276
277
278 /* that's it. return the token */
279
280 (*seqnum)++;
281 *seqnum &= 0xffffffffL;
282
283 token->length = tlen;
284 token->value = (void *) t;
285
286 return(0);
287 }
288
289 /* if signonly is true, ignore conf_req, conf_state,
290 and do not encode the ENC_TYPE, MSG_LENGTH, or MSG_TEXT fields */
291
292 OM_uint32
kg_seal(OM_uint32 * minor_status,gss_ctx_id_t context_handle,int conf_req_flag,gss_qop_t qop_req,gss_buffer_t input_message_buffer,int * conf_state,gss_buffer_t output_message_buffer,int toktype)293 kg_seal(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
294 int conf_req_flag, gss_qop_t qop_req,
295 gss_buffer_t input_message_buffer, int *conf_state,
296 gss_buffer_t output_message_buffer, int toktype)
297 {
298 krb5_gss_ctx_id_rec *ctx;
299 krb5_error_code code;
300 krb5_context context;
301
302 output_message_buffer->length = 0;
303 output_message_buffer->value = NULL;
304
305 /* Only default qop or matching established cryptosystem is allowed.
306
307 There are NO EXTENSIONS to this set for AES and friends! The
308 new spec says "just use 0". The old spec plus extensions would
309 actually allow for certain non-zero values. Fix this to handle
310 them later. */
311 if (qop_req != 0) {
312 *minor_status = (OM_uint32) G_UNKNOWN_QOP;
313 return GSS_S_BAD_QOP;
314 }
315
316 ctx = (krb5_gss_ctx_id_rec *) context_handle;
317
318 if (ctx->terminated || !ctx->established) {
319 *minor_status = KG_CTX_INCOMPLETE;
320 return(GSS_S_NO_CONTEXT);
321 }
322
323 context = ctx->k5_context;
324 switch (ctx->proto)
325 {
326 case 0:
327 code = make_seal_token_v1(context, ctx->enc, ctx->seq,
328 &ctx->seq_send, ctx->initiate,
329 input_message_buffer, output_message_buffer,
330 ctx->signalg, ctx->cksum_size, ctx->sealalg,
331 conf_req_flag, toktype, ctx->mech_used);
332 break;
333 case 1:
334 code = gss_krb5int_make_seal_token_v3(context, ctx,
335 input_message_buffer,
336 output_message_buffer,
337 conf_req_flag, toktype);
338 break;
339 default:
340 code = G_UNKNOWN_QOP; /* XXX */
341 break;
342 }
343
344 if (code) {
345 *minor_status = code;
346 save_error_info(*minor_status, context);
347 return(GSS_S_FAILURE);
348 }
349
350 if (conf_state)
351 *conf_state = conf_req_flag;
352
353 *minor_status = 0;
354 return(GSS_S_COMPLETE);
355 }
356
357 OM_uint32 KRB5_CALLCONV
krb5_gss_wrap(OM_uint32 * minor_status,gss_ctx_id_t context_handle,int conf_req_flag,gss_qop_t qop_req,gss_buffer_t input_message_buffer,int * conf_state,gss_buffer_t output_message_buffer)358 krb5_gss_wrap(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
359 int conf_req_flag, gss_qop_t qop_req,
360 gss_buffer_t input_message_buffer, int *conf_state,
361 gss_buffer_t output_message_buffer)
362 {
363 return(kg_seal(minor_status, context_handle, conf_req_flag,
364 qop_req, input_message_buffer, conf_state,
365 output_message_buffer, KG_TOK_WRAP_MSG));
366 }
367
368 OM_uint32 KRB5_CALLCONV
krb5_gss_get_mic(OM_uint32 * minor_status,gss_ctx_id_t context_handle,gss_qop_t qop_req,gss_buffer_t message_buffer,gss_buffer_t message_token)369 krb5_gss_get_mic(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
370 gss_qop_t qop_req, gss_buffer_t message_buffer,
371 gss_buffer_t message_token)
372 {
373 return(kg_seal(minor_status, context_handle, 0,
374 qop_req, message_buffer, NULL,
375 message_token, KG_TOK_MIC_MSG));
376 }
377