fix typo
[heimdal.git] / lib / gssapi / krb5 / wrap.c
blobe2b8d6cd1a273023beb5deafdf573c080e35c56e
1 /*
2 * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
34 #include "gssapi_locl.h"
36 RCSID("$Id$");
38 static OM_uint32
39 sub_wrap_size (
40 OM_uint32 req_output_size,
41 OM_uint32 * max_input_size,
42 int blocksize,
43 int extrasize
46 size_t len, total_len, padlength;
47 padlength = blocksize - (req_output_size % blocksize);
48 len = req_output_size + 8 + padlength + extrasize;
49 gssapi_krb5_encap_length(len, &len, &total_len);
50 *max_input_size = (OM_uint32)total_len;
51 return GSS_S_COMPLETE;
54 OM_uint32
55 gss_wrap_size_limit (
56 OM_uint32 * minor_status,
57 const gss_ctx_id_t context_handle,
58 int conf_req_flag,
59 gss_qop_t qop_req,
60 OM_uint32 req_output_size,
61 OM_uint32 * max_input_size
64 krb5_keyblock *key;
65 OM_uint32 ret;
66 krb5_keytype keytype;
68 ret = gss_krb5_getsomekey(context_handle, &key);
69 if (ret) {
70 *minor_status = ret;
71 return GSS_S_FAILURE;
73 krb5_enctype_to_keytype (gssapi_krb5_context, key->keytype, &keytype);
75 switch (keytype) {
76 case KEYTYPE_DES :
77 ret = sub_wrap_size(req_output_size, max_input_size, 8, 22);
78 break;
79 case KEYTYPE_DES3 :
80 ret = sub_wrap_size(req_output_size, max_input_size, 8, 34);
81 break;
82 default :
83 *minor_status = KRB5_PROG_ETYPE_NOSUPP;
84 ret = GSS_S_FAILURE;
85 break;
87 krb5_free_keyblock (gssapi_krb5_context, key);
88 return ret;
91 static OM_uint32
92 wrap_des
93 (OM_uint32 * minor_status,
94 const gss_ctx_id_t context_handle,
95 int conf_req_flag,
96 gss_qop_t qop_req,
97 const gss_buffer_t input_message_buffer,
98 int * conf_state,
99 gss_buffer_t output_message_buffer,
100 krb5_keyblock *key
103 u_char *p;
104 MD5_CTX md5;
105 u_char hash[16];
106 des_key_schedule schedule;
107 des_cblock deskey;
108 des_cblock zero;
109 int i;
110 int32_t seq_number;
111 size_t len, total_len, padlength, datalen;
113 padlength = 8 - (input_message_buffer->length % 8);
114 datalen = input_message_buffer->length + padlength + 8;
115 len = datalen + 22;
116 gssapi_krb5_encap_length (len, &len, &total_len);
118 output_message_buffer->length = total_len;
119 output_message_buffer->value = malloc (total_len);
120 if (output_message_buffer->value == NULL)
121 return GSS_S_FAILURE;
123 p = gssapi_krb5_make_header(output_message_buffer->value,
124 len,
125 "\x02\x01"); /* TOK_ID */
127 /* SGN_ALG */
128 memcpy (p, "\x00\x00", 2);
129 p += 2;
130 /* SEAL_ALG */
131 if(conf_req_flag)
132 memcpy (p, "\x00\x00", 2);
133 else
134 memcpy (p, "\xff\xff", 2);
135 p += 2;
136 /* Filler */
137 memcpy (p, "\xff\xff", 2);
138 p += 2;
140 /* fill in later */
141 memset (p, 0, 16);
142 p += 16;
144 /* confounder + data + pad */
145 des_new_random_key((des_cblock*)p);
146 memcpy (p + 8, input_message_buffer->value,
147 input_message_buffer->length);
148 memset (p + 8 + input_message_buffer->length, padlength, padlength);
150 /* checksum */
151 MD5_Init (&md5);
152 MD5_Update (&md5, p - 24, 8);
153 MD5_Update (&md5, p, datalen);
154 MD5_Final (hash, &md5);
156 memset (&zero, 0, sizeof(zero));
157 memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
158 des_set_key (&deskey, schedule);
159 des_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
160 schedule, &zero);
161 memcpy (p - 8, hash, 8);
163 /* sequence number */
164 krb5_auth_getlocalseqnumber (gssapi_krb5_context,
165 context_handle->auth_context,
166 &seq_number);
168 p -= 16;
169 p[0] = (seq_number >> 0) & 0xFF;
170 p[1] = (seq_number >> 8) & 0xFF;
171 p[2] = (seq_number >> 16) & 0xFF;
172 p[3] = (seq_number >> 24) & 0xFF;
173 memset (p + 4,
174 (context_handle->more_flags & LOCAL) ? 0 : 0xFF,
177 des_set_key (&deskey, schedule);
178 des_cbc_encrypt ((void *)p, (void *)p, 8,
179 schedule, (des_cblock *)(p + 8), DES_ENCRYPT);
181 krb5_auth_setlocalseqnumber (gssapi_krb5_context,
182 context_handle->auth_context,
183 ++seq_number);
185 /* encrypt the data */
186 p += 16;
188 if(conf_req_flag) {
189 memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
191 for (i = 0; i < sizeof(deskey); ++i)
192 deskey[i] ^= 0xf0;
193 des_set_key (&deskey, schedule);
194 memset (&zero, 0, sizeof(zero));
195 des_cbc_encrypt ((void *)p,
196 (void *)p,
197 datalen,
198 schedule,
199 &zero,
200 DES_ENCRYPT);
202 memset (deskey, 0, sizeof(deskey));
203 memset (schedule, 0, sizeof(schedule));
205 if(conf_state != NULL)
206 *conf_state = conf_req_flag;
207 return GSS_S_COMPLETE;
210 static OM_uint32
211 wrap_des3
212 (OM_uint32 * minor_status,
213 const gss_ctx_id_t context_handle,
214 int conf_req_flag,
215 gss_qop_t qop_req,
216 const gss_buffer_t input_message_buffer,
217 int * conf_state,
218 gss_buffer_t output_message_buffer,
219 krb5_keyblock *key
222 u_char *p;
223 u_char seq[8];
224 int32_t seq_number;
225 size_t len, total_len, padlength, datalen;
226 u_int32_t ret;
227 krb5_crypto crypto;
228 Checksum cksum;
229 krb5_data encdata;
231 padlength = 8 - (input_message_buffer->length % 8);
232 datalen = input_message_buffer->length + padlength + 8;
233 len = datalen + 34;
234 gssapi_krb5_encap_length (len, &len, &total_len);
236 output_message_buffer->length = total_len;
237 output_message_buffer->value = malloc (total_len);
238 if (output_message_buffer->value == NULL)
239 return GSS_S_FAILURE;
241 p = gssapi_krb5_make_header(output_message_buffer->value,
242 len,
243 "\x02\x01"); /* TOK_ID */
245 /* SGN_ALG */
246 memcpy (p, "\x04\x00", 2); /* HMAC SHA1 DES3-KD */
247 p += 2;
248 /* SEAL_ALG */
249 if(conf_req_flag)
250 memcpy (p, "\x02\x00", 2); /* DES3-KD */
251 else
252 memcpy (p, "\xff\xff", 2);
253 p += 2;
254 /* Filler */
255 memcpy (p, "\xff\xff", 2);
256 p += 2;
258 /* calculate checksum (the above + confounder + data + pad) */
260 memcpy (p + 20, p - 8, 8);
261 des_new_random_key((des_cblock*)(p + 28));
262 memcpy (p + 28 + 8, input_message_buffer->value,
263 input_message_buffer->length);
264 memset (p + 28 + 8 + input_message_buffer->length, padlength, padlength);
266 ret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto);
267 if (ret) {
268 free (output_message_buffer->value);
269 *minor_status = ret;
270 return GSS_S_FAILURE;
273 ret = krb5_create_checksum (gssapi_krb5_context,
274 crypto,
275 KRB5_KU_USAGE_SIGN,
276 p + 20,
277 datalen + 8,
278 &cksum);
279 krb5_crypto_destroy (gssapi_krb5_context, crypto);
280 if (ret) {
281 free (output_message_buffer->value);
282 *minor_status = ret;
283 return GSS_S_FAILURE;
286 /* zero out SND_SEQ + SGN_CKSUM in case */
287 memset (p, 0, 28);
289 memcpy (p + 8, cksum.checksum.data, cksum.checksum.length);
290 free_Checksum (&cksum);
292 /* sequence number */
293 krb5_auth_getlocalseqnumber (gssapi_krb5_context,
294 context_handle->auth_context,
295 &seq_number);
297 seq[0] = (seq_number >> 0) & 0xFF;
298 seq[1] = (seq_number >> 8) & 0xFF;
299 seq[2] = (seq_number >> 16) & 0xFF;
300 seq[3] = (seq_number >> 24) & 0xFF;
301 memset (seq + 4,
302 (context_handle->more_flags & LOCAL) ? 0 : 0xFF,
306 ret = krb5_crypto_init(gssapi_krb5_context, key, ETYPE_DES3_CBC_NONE_IVEC,
307 &crypto);
308 if (ret) {
309 free (output_message_buffer->value);
310 *minor_status = ret;
311 return GSS_S_FAILURE;
315 des_cblock ivec;
317 memcpy (&ivec, p + 8, 8);
318 ret = krb5_encrypt_ivec (gssapi_krb5_context,
319 crypto,
320 KRB5_KU_USAGE_SEQ,
321 seq, 8, &encdata,
322 &ivec);
324 krb5_crypto_destroy (gssapi_krb5_context, crypto);
325 if (ret) {
326 free (output_message_buffer->value);
327 *minor_status = ret;
328 return GSS_S_FAILURE;
331 assert (encdata.length == 8);
333 memcpy (p, encdata.data, encdata.length);
334 krb5_data_free (&encdata);
336 krb5_auth_setlocalseqnumber (gssapi_krb5_context,
337 context_handle->auth_context,
338 ++seq_number);
340 /* encrypt the data */
341 p += 28;
343 if(conf_req_flag) {
344 krb5_data tmp;
346 ret = krb5_crypto_init(gssapi_krb5_context, key,
347 ETYPE_DES3_CBC_NONE, &crypto);
348 if (ret) {
349 free (output_message_buffer->value);
350 *minor_status = ret;
351 return GSS_S_FAILURE;
353 ret = krb5_encrypt(gssapi_krb5_context, crypto, KRB5_KU_USAGE_SEAL,
354 p, datalen, &tmp);
355 krb5_crypto_destroy(gssapi_krb5_context, crypto);
356 if (ret) {
357 free (output_message_buffer->value);
358 *minor_status = ret;
359 return GSS_S_FAILURE;
361 assert (tmp.length == datalen);
363 memcpy (p, tmp.data, datalen);
364 krb5_data_free(&tmp);
366 if(conf_state != NULL)
367 *conf_state = conf_req_flag;
368 return GSS_S_COMPLETE;
371 OM_uint32 gss_wrap
372 (OM_uint32 * minor_status,
373 const gss_ctx_id_t context_handle,
374 int conf_req_flag,
375 gss_qop_t qop_req,
376 const gss_buffer_t input_message_buffer,
377 int * conf_state,
378 gss_buffer_t output_message_buffer
381 krb5_keyblock *key;
382 OM_uint32 ret;
383 krb5_keytype keytype;
385 ret = gss_krb5_getsomekey(context_handle, &key);
386 if (ret) {
387 *minor_status = ret;
388 return GSS_S_FAILURE;
390 krb5_enctype_to_keytype (gssapi_krb5_context, key->keytype, &keytype);
392 switch (keytype) {
393 case KEYTYPE_DES :
394 ret = wrap_des (minor_status, context_handle, conf_req_flag,
395 qop_req, input_message_buffer, conf_state,
396 output_message_buffer, key);
397 break;
398 case KEYTYPE_DES3 :
399 ret = wrap_des3 (minor_status, context_handle, conf_req_flag,
400 qop_req, input_message_buffer, conf_state,
401 output_message_buffer, key);
402 break;
403 default :
404 *minor_status = KRB5_PROG_ETYPE_NOSUPP;
405 ret = GSS_S_FAILURE;
406 break;
408 krb5_free_keyblock (gssapi_krb5_context, key);
409 return ret;