1c19800e8SDoug Rabson /*
2ae771770SStanislav Sedov * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
3c19800e8SDoug Rabson * (Royal Institute of Technology, Stockholm, Sweden).
4c19800e8SDoug Rabson * All rights reserved.
5c19800e8SDoug Rabson *
6c19800e8SDoug Rabson * Redistribution and use in source and binary forms, with or without
7c19800e8SDoug Rabson * modification, are permitted provided that the following conditions
8c19800e8SDoug Rabson * are met:
9c19800e8SDoug Rabson *
10c19800e8SDoug Rabson * 1. Redistributions of source code must retain the above copyright
11c19800e8SDoug Rabson * notice, this list of conditions and the following disclaimer.
12c19800e8SDoug Rabson *
13c19800e8SDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright
14c19800e8SDoug Rabson * notice, this list of conditions and the following disclaimer in the
15c19800e8SDoug Rabson * documentation and/or other materials provided with the distribution.
16c19800e8SDoug Rabson *
17c19800e8SDoug Rabson * 3. Neither the name of the Institute nor the names of its contributors
18c19800e8SDoug Rabson * may be used to endorse or promote products derived from this software
19c19800e8SDoug Rabson * without specific prior written permission.
20c19800e8SDoug Rabson *
21c19800e8SDoug Rabson * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22c19800e8SDoug Rabson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23c19800e8SDoug Rabson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24c19800e8SDoug Rabson * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25c19800e8SDoug Rabson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26c19800e8SDoug Rabson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27c19800e8SDoug Rabson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28c19800e8SDoug Rabson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29c19800e8SDoug Rabson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30c19800e8SDoug Rabson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31c19800e8SDoug Rabson * SUCH DAMAGE.
32c19800e8SDoug Rabson */
33c19800e8SDoug Rabson
34ae771770SStanislav Sedov #include "gsskrb5_locl.h"
35c19800e8SDoug Rabson
36c19800e8SDoug Rabson /*
37c19800e8SDoug Rabson * Return initiator subkey, or if that doesn't exists, the subkey.
38c19800e8SDoug Rabson */
39c19800e8SDoug Rabson
40c19800e8SDoug Rabson krb5_error_code
_gsskrb5i_get_initiator_subkey(const gsskrb5_ctx ctx,krb5_context context,krb5_keyblock ** key)41c19800e8SDoug Rabson _gsskrb5i_get_initiator_subkey(const gsskrb5_ctx ctx,
42c19800e8SDoug Rabson krb5_context context,
43c19800e8SDoug Rabson krb5_keyblock **key)
44c19800e8SDoug Rabson {
45c19800e8SDoug Rabson krb5_error_code ret;
46c19800e8SDoug Rabson *key = NULL;
47c19800e8SDoug Rabson
48c19800e8SDoug Rabson if (ctx->more_flags & LOCAL) {
49c19800e8SDoug Rabson ret = krb5_auth_con_getlocalsubkey(context,
50c19800e8SDoug Rabson ctx->auth_context,
51c19800e8SDoug Rabson key);
52c19800e8SDoug Rabson } else {
53c19800e8SDoug Rabson ret = krb5_auth_con_getremotesubkey(context,
54c19800e8SDoug Rabson ctx->auth_context,
55c19800e8SDoug Rabson key);
56c19800e8SDoug Rabson }
57c19800e8SDoug Rabson if (ret == 0 && *key == NULL)
58c19800e8SDoug Rabson ret = krb5_auth_con_getkey(context,
59c19800e8SDoug Rabson ctx->auth_context,
60c19800e8SDoug Rabson key);
61c19800e8SDoug Rabson if (ret == 0 && *key == NULL) {
62ae771770SStanislav Sedov krb5_set_error_message(context, 0, "No initiator subkey available");
63c19800e8SDoug Rabson return GSS_KRB5_S_KG_NO_SUBKEY;
64c19800e8SDoug Rabson }
65c19800e8SDoug Rabson return ret;
66c19800e8SDoug Rabson }
67c19800e8SDoug Rabson
68c19800e8SDoug Rabson krb5_error_code
_gsskrb5i_get_acceptor_subkey(const gsskrb5_ctx ctx,krb5_context context,krb5_keyblock ** key)69c19800e8SDoug Rabson _gsskrb5i_get_acceptor_subkey(const gsskrb5_ctx ctx,
70c19800e8SDoug Rabson krb5_context context,
71c19800e8SDoug Rabson krb5_keyblock **key)
72c19800e8SDoug Rabson {
73c19800e8SDoug Rabson krb5_error_code ret;
74c19800e8SDoug Rabson *key = NULL;
75c19800e8SDoug Rabson
76c19800e8SDoug Rabson if (ctx->more_flags & LOCAL) {
77c19800e8SDoug Rabson ret = krb5_auth_con_getremotesubkey(context,
78c19800e8SDoug Rabson ctx->auth_context,
79c19800e8SDoug Rabson key);
80c19800e8SDoug Rabson } else {
81c19800e8SDoug Rabson ret = krb5_auth_con_getlocalsubkey(context,
82c19800e8SDoug Rabson ctx->auth_context,
83c19800e8SDoug Rabson key);
84c19800e8SDoug Rabson }
85c19800e8SDoug Rabson if (ret == 0 && *key == NULL) {
86ae771770SStanislav Sedov krb5_set_error_message(context, 0, "No acceptor subkey available");
87c19800e8SDoug Rabson return GSS_KRB5_S_KG_NO_SUBKEY;
88c19800e8SDoug Rabson }
89c19800e8SDoug Rabson return ret;
90c19800e8SDoug Rabson }
91c19800e8SDoug Rabson
92c19800e8SDoug Rabson OM_uint32
_gsskrb5i_get_token_key(const gsskrb5_ctx ctx,krb5_context context,krb5_keyblock ** key)93c19800e8SDoug Rabson _gsskrb5i_get_token_key(const gsskrb5_ctx ctx,
94c19800e8SDoug Rabson krb5_context context,
95c19800e8SDoug Rabson krb5_keyblock **key)
96c19800e8SDoug Rabson {
97c19800e8SDoug Rabson _gsskrb5i_get_acceptor_subkey(ctx, context, key);
98c19800e8SDoug Rabson if(*key == NULL) {
99c19800e8SDoug Rabson /*
100c19800e8SDoug Rabson * Only use the initiator subkey or ticket session key if an
101c19800e8SDoug Rabson * acceptor subkey was not required.
102c19800e8SDoug Rabson */
103c19800e8SDoug Rabson if ((ctx->more_flags & ACCEPTOR_SUBKEY) == 0)
104c19800e8SDoug Rabson _gsskrb5i_get_initiator_subkey(ctx, context, key);
105c19800e8SDoug Rabson }
106c19800e8SDoug Rabson if (*key == NULL) {
107ae771770SStanislav Sedov krb5_set_error_message(context, 0, "No token key available");
108c19800e8SDoug Rabson return GSS_KRB5_S_KG_NO_SUBKEY;
109c19800e8SDoug Rabson }
110c19800e8SDoug Rabson return 0;
111c19800e8SDoug Rabson }
112c19800e8SDoug Rabson
113c19800e8SDoug Rabson static OM_uint32
sub_wrap_size(OM_uint32 req_output_size,OM_uint32 * max_input_size,int blocksize,int extrasize)114c19800e8SDoug Rabson sub_wrap_size (
115c19800e8SDoug Rabson OM_uint32 req_output_size,
116c19800e8SDoug Rabson OM_uint32 * max_input_size,
117c19800e8SDoug Rabson int blocksize,
118c19800e8SDoug Rabson int extrasize
119c19800e8SDoug Rabson )
120c19800e8SDoug Rabson {
121c19800e8SDoug Rabson size_t len, total_len;
122c19800e8SDoug Rabson
123c19800e8SDoug Rabson len = 8 + req_output_size + blocksize + extrasize;
124c19800e8SDoug Rabson
125c19800e8SDoug Rabson _gsskrb5_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
126c19800e8SDoug Rabson
127c19800e8SDoug Rabson total_len -= req_output_size; /* token length */
128c19800e8SDoug Rabson if (total_len < req_output_size) {
129c19800e8SDoug Rabson *max_input_size = (req_output_size - total_len);
130c19800e8SDoug Rabson (*max_input_size) &= (~(OM_uint32)(blocksize - 1));
131c19800e8SDoug Rabson } else {
132c19800e8SDoug Rabson *max_input_size = 0;
133c19800e8SDoug Rabson }
134c19800e8SDoug Rabson return GSS_S_COMPLETE;
135c19800e8SDoug Rabson }
136c19800e8SDoug Rabson
137ae771770SStanislav Sedov OM_uint32 GSSAPI_CALLCONV
_gsskrb5_wrap_size_limit(OM_uint32 * minor_status,const gss_ctx_id_t context_handle,int conf_req_flag,gss_qop_t qop_req,OM_uint32 req_output_size,OM_uint32 * max_input_size)138c19800e8SDoug Rabson _gsskrb5_wrap_size_limit (
139c19800e8SDoug Rabson OM_uint32 * minor_status,
140c19800e8SDoug Rabson const gss_ctx_id_t context_handle,
141c19800e8SDoug Rabson int conf_req_flag,
142c19800e8SDoug Rabson gss_qop_t qop_req,
143c19800e8SDoug Rabson OM_uint32 req_output_size,
144c19800e8SDoug Rabson OM_uint32 * max_input_size
145c19800e8SDoug Rabson )
146c19800e8SDoug Rabson {
147c19800e8SDoug Rabson krb5_context context;
148c19800e8SDoug Rabson krb5_keyblock *key;
149c19800e8SDoug Rabson OM_uint32 ret;
150c19800e8SDoug Rabson krb5_keytype keytype;
151c19800e8SDoug Rabson const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
152c19800e8SDoug Rabson
153c19800e8SDoug Rabson GSSAPI_KRB5_INIT (&context);
154c19800e8SDoug Rabson
155ae771770SStanislav Sedov if (ctx->more_flags & IS_CFX)
156ae771770SStanislav Sedov return _gssapi_wrap_size_cfx(minor_status, ctx, context,
157ae771770SStanislav Sedov conf_req_flag, qop_req,
158ae771770SStanislav Sedov req_output_size, max_input_size);
159ae771770SStanislav Sedov
160c19800e8SDoug Rabson HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
161c19800e8SDoug Rabson ret = _gsskrb5i_get_token_key(ctx, context, &key);
162c19800e8SDoug Rabson HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
163c19800e8SDoug Rabson if (ret) {
164c19800e8SDoug Rabson *minor_status = ret;
165c19800e8SDoug Rabson return GSS_S_FAILURE;
166c19800e8SDoug Rabson }
167c19800e8SDoug Rabson krb5_enctype_to_keytype (context, key->keytype, &keytype);
168c19800e8SDoug Rabson
169c19800e8SDoug Rabson switch (keytype) {
170c19800e8SDoug Rabson case KEYTYPE_DES :
171ae771770SStanislav Sedov #ifdef HEIM_WEAK_CRYPTO
172c19800e8SDoug Rabson ret = sub_wrap_size(req_output_size, max_input_size, 8, 22);
173ae771770SStanislav Sedov #else
174ae771770SStanislav Sedov ret = GSS_S_FAILURE;
175ae771770SStanislav Sedov #endif
176c19800e8SDoug Rabson break;
177ae771770SStanislav Sedov case ENCTYPE_ARCFOUR_HMAC_MD5:
178ae771770SStanislav Sedov case ENCTYPE_ARCFOUR_HMAC_MD5_56:
179c19800e8SDoug Rabson ret = _gssapi_wrap_size_arcfour(minor_status, ctx, context,
180c19800e8SDoug Rabson conf_req_flag, qop_req,
181c19800e8SDoug Rabson req_output_size, max_input_size, key);
182c19800e8SDoug Rabson break;
183c19800e8SDoug Rabson case KEYTYPE_DES3 :
184c19800e8SDoug Rabson ret = sub_wrap_size(req_output_size, max_input_size, 8, 34);
185c19800e8SDoug Rabson break;
186c19800e8SDoug Rabson default :
187ae771770SStanislav Sedov abort();
188c19800e8SDoug Rabson break;
189c19800e8SDoug Rabson }
190c19800e8SDoug Rabson krb5_free_keyblock (context, key);
191c19800e8SDoug Rabson *minor_status = 0;
192c19800e8SDoug Rabson return ret;
193c19800e8SDoug Rabson }
194c19800e8SDoug Rabson
195ae771770SStanislav Sedov #ifdef HEIM_WEAK_CRYPTO
196ae771770SStanislav Sedov
197c19800e8SDoug Rabson static OM_uint32
wrap_des(OM_uint32 * minor_status,const gsskrb5_ctx ctx,krb5_context context,int conf_req_flag,gss_qop_t qop_req,const gss_buffer_t input_message_buffer,int * conf_state,gss_buffer_t output_message_buffer,krb5_keyblock * key)198c19800e8SDoug Rabson wrap_des
199c19800e8SDoug Rabson (OM_uint32 * minor_status,
200c19800e8SDoug Rabson const gsskrb5_ctx ctx,
201c19800e8SDoug Rabson krb5_context context,
202c19800e8SDoug Rabson int conf_req_flag,
203c19800e8SDoug Rabson gss_qop_t qop_req,
204c19800e8SDoug Rabson const gss_buffer_t input_message_buffer,
205c19800e8SDoug Rabson int * conf_state,
206c19800e8SDoug Rabson gss_buffer_t output_message_buffer,
207c19800e8SDoug Rabson krb5_keyblock *key
208c19800e8SDoug Rabson )
209c19800e8SDoug Rabson {
210c19800e8SDoug Rabson u_char *p;
211ae771770SStanislav Sedov EVP_MD_CTX *md5;
212c19800e8SDoug Rabson u_char hash[16];
213c19800e8SDoug Rabson DES_key_schedule schedule;
214*e4456411SJohn Baldwin EVP_CIPHER_CTX *des_ctx;
215c19800e8SDoug Rabson DES_cblock deskey;
216c19800e8SDoug Rabson DES_cblock zero;
217ae771770SStanislav Sedov size_t i;
218c19800e8SDoug Rabson int32_t seq_number;
219c19800e8SDoug Rabson size_t len, total_len, padlength, datalen;
220c19800e8SDoug Rabson
221ae771770SStanislav Sedov if (IS_DCE_STYLE(ctx)) {
222ae771770SStanislav Sedov padlength = 0;
223ae771770SStanislav Sedov datalen = input_message_buffer->length;
224ae771770SStanislav Sedov len = 22 + 8;
225ae771770SStanislav Sedov _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
226ae771770SStanislav Sedov total_len += datalen;
227ae771770SStanislav Sedov datalen += 8;
228ae771770SStanislav Sedov } else {
229c19800e8SDoug Rabson padlength = 8 - (input_message_buffer->length % 8);
230c19800e8SDoug Rabson datalen = input_message_buffer->length + padlength + 8;
231c19800e8SDoug Rabson len = datalen + 22;
232c19800e8SDoug Rabson _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
233ae771770SStanislav Sedov }
234c19800e8SDoug Rabson
235c19800e8SDoug Rabson output_message_buffer->length = total_len;
236c19800e8SDoug Rabson output_message_buffer->value = malloc (total_len);
237c19800e8SDoug Rabson if (output_message_buffer->value == NULL) {
238c19800e8SDoug Rabson output_message_buffer->length = 0;
239c19800e8SDoug Rabson *minor_status = ENOMEM;
240c19800e8SDoug Rabson return GSS_S_FAILURE;
241c19800e8SDoug Rabson }
242c19800e8SDoug Rabson
243c19800e8SDoug Rabson p = _gsskrb5_make_header(output_message_buffer->value,
244c19800e8SDoug Rabson len,
245c19800e8SDoug Rabson "\x02\x01", /* TOK_ID */
246c19800e8SDoug Rabson GSS_KRB5_MECHANISM);
247c19800e8SDoug Rabson
248c19800e8SDoug Rabson /* SGN_ALG */
249c19800e8SDoug Rabson memcpy (p, "\x00\x00", 2);
250c19800e8SDoug Rabson p += 2;
251c19800e8SDoug Rabson /* SEAL_ALG */
252c19800e8SDoug Rabson if(conf_req_flag)
253c19800e8SDoug Rabson memcpy (p, "\x00\x00", 2);
254c19800e8SDoug Rabson else
255c19800e8SDoug Rabson memcpy (p, "\xff\xff", 2);
256c19800e8SDoug Rabson p += 2;
257c19800e8SDoug Rabson /* Filler */
258c19800e8SDoug Rabson memcpy (p, "\xff\xff", 2);
259c19800e8SDoug Rabson p += 2;
260c19800e8SDoug Rabson
261c19800e8SDoug Rabson /* fill in later */
262c19800e8SDoug Rabson memset (p, 0, 16);
263c19800e8SDoug Rabson p += 16;
264c19800e8SDoug Rabson
265c19800e8SDoug Rabson /* confounder + data + pad */
266c19800e8SDoug Rabson krb5_generate_random_block(p, 8);
267c19800e8SDoug Rabson memcpy (p + 8, input_message_buffer->value,
268c19800e8SDoug Rabson input_message_buffer->length);
269c19800e8SDoug Rabson memset (p + 8 + input_message_buffer->length, padlength, padlength);
270c19800e8SDoug Rabson
271c19800e8SDoug Rabson /* checksum */
272ae771770SStanislav Sedov md5 = EVP_MD_CTX_create();
273ae771770SStanislav Sedov EVP_DigestInit_ex(md5, EVP_md5(), NULL);
274ae771770SStanislav Sedov EVP_DigestUpdate(md5, p - 24, 8);
275ae771770SStanislav Sedov EVP_DigestUpdate(md5, p, datalen);
276ae771770SStanislav Sedov EVP_DigestFinal_ex(md5, hash, NULL);
277ae771770SStanislav Sedov EVP_MD_CTX_destroy(md5);
278c19800e8SDoug Rabson
279c19800e8SDoug Rabson memset (&zero, 0, sizeof(zero));
280c19800e8SDoug Rabson memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
281ae771770SStanislav Sedov DES_set_key_unchecked (&deskey, &schedule);
282c19800e8SDoug Rabson DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
283c19800e8SDoug Rabson &schedule, &zero);
284c19800e8SDoug Rabson memcpy (p - 8, hash, 8);
285c19800e8SDoug Rabson
286*e4456411SJohn Baldwin des_ctx = EVP_CIPHER_CTX_new();
287*e4456411SJohn Baldwin if (des_ctx == NULL) {
288*e4456411SJohn Baldwin memset (deskey, 0, sizeof(deskey));
289*e4456411SJohn Baldwin memset (&schedule, 0, sizeof(schedule));
290*e4456411SJohn Baldwin free(output_message_buffer->value);
291*e4456411SJohn Baldwin output_message_buffer->value = NULL;
292*e4456411SJohn Baldwin output_message_buffer->length = 0;
293*e4456411SJohn Baldwin *minor_status = ENOMEM;
294*e4456411SJohn Baldwin return GSS_S_FAILURE;
295*e4456411SJohn Baldwin }
296*e4456411SJohn Baldwin
297c19800e8SDoug Rabson /* sequence number */
298c19800e8SDoug Rabson HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
299c19800e8SDoug Rabson krb5_auth_con_getlocalseqnumber (context,
300c19800e8SDoug Rabson ctx->auth_context,
301c19800e8SDoug Rabson &seq_number);
302c19800e8SDoug Rabson
303c19800e8SDoug Rabson p -= 16;
304c19800e8SDoug Rabson p[0] = (seq_number >> 0) & 0xFF;
305c19800e8SDoug Rabson p[1] = (seq_number >> 8) & 0xFF;
306c19800e8SDoug Rabson p[2] = (seq_number >> 16) & 0xFF;
307c19800e8SDoug Rabson p[3] = (seq_number >> 24) & 0xFF;
308c19800e8SDoug Rabson memset (p + 4,
309c19800e8SDoug Rabson (ctx->more_flags & LOCAL) ? 0 : 0xFF,
310c19800e8SDoug Rabson 4);
311c19800e8SDoug Rabson
312*e4456411SJohn Baldwin EVP_CipherInit_ex(des_ctx, EVP_des_cbc(), NULL, key->keyvalue.data, p + 8, 1);
313*e4456411SJohn Baldwin EVP_Cipher(des_ctx, p, p, 8);
314c19800e8SDoug Rabson
315c19800e8SDoug Rabson krb5_auth_con_setlocalseqnumber (context,
316c19800e8SDoug Rabson ctx->auth_context,
317c19800e8SDoug Rabson ++seq_number);
318c19800e8SDoug Rabson HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
319c19800e8SDoug Rabson
320c19800e8SDoug Rabson /* encrypt the data */
321c19800e8SDoug Rabson p += 16;
322c19800e8SDoug Rabson
323c19800e8SDoug Rabson if(conf_req_flag) {
324c19800e8SDoug Rabson memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
325c19800e8SDoug Rabson
326c19800e8SDoug Rabson for (i = 0; i < sizeof(deskey); ++i)
327c19800e8SDoug Rabson deskey[i] ^= 0xf0;
328ae771770SStanislav Sedov
329*e4456411SJohn Baldwin EVP_CIPHER_CTX_reset(des_ctx);
330*e4456411SJohn Baldwin EVP_CipherInit_ex(des_ctx, EVP_des_cbc(), NULL, deskey, zero, 1);
331*e4456411SJohn Baldwin EVP_Cipher(des_ctx, p, p, datalen);
332c19800e8SDoug Rabson }
333*e4456411SJohn Baldwin EVP_CIPHER_CTX_free(des_ctx);
334c19800e8SDoug Rabson memset (deskey, 0, sizeof(deskey));
335c19800e8SDoug Rabson memset (&schedule, 0, sizeof(schedule));
336c19800e8SDoug Rabson
337c19800e8SDoug Rabson if(conf_state != NULL)
338c19800e8SDoug Rabson *conf_state = conf_req_flag;
339c19800e8SDoug Rabson *minor_status = 0;
340c19800e8SDoug Rabson return GSS_S_COMPLETE;
341c19800e8SDoug Rabson }
342c19800e8SDoug Rabson
343ae771770SStanislav Sedov #endif
344ae771770SStanislav Sedov
345c19800e8SDoug Rabson static OM_uint32
wrap_des3(OM_uint32 * minor_status,const gsskrb5_ctx ctx,krb5_context context,int conf_req_flag,gss_qop_t qop_req,const gss_buffer_t input_message_buffer,int * conf_state,gss_buffer_t output_message_buffer,krb5_keyblock * key)346c19800e8SDoug Rabson wrap_des3
347c19800e8SDoug Rabson (OM_uint32 * minor_status,
348c19800e8SDoug Rabson const gsskrb5_ctx ctx,
349c19800e8SDoug Rabson krb5_context context,
350c19800e8SDoug Rabson int conf_req_flag,
351c19800e8SDoug Rabson gss_qop_t qop_req,
352c19800e8SDoug Rabson const gss_buffer_t input_message_buffer,
353c19800e8SDoug Rabson int * conf_state,
354c19800e8SDoug Rabson gss_buffer_t output_message_buffer,
355c19800e8SDoug Rabson krb5_keyblock *key
356c19800e8SDoug Rabson )
357c19800e8SDoug Rabson {
358c19800e8SDoug Rabson u_char *p;
359c19800e8SDoug Rabson u_char seq[8];
360c19800e8SDoug Rabson int32_t seq_number;
361c19800e8SDoug Rabson size_t len, total_len, padlength, datalen;
362c19800e8SDoug Rabson uint32_t ret;
363c19800e8SDoug Rabson krb5_crypto crypto;
364c19800e8SDoug Rabson Checksum cksum;
365c19800e8SDoug Rabson krb5_data encdata;
366c19800e8SDoug Rabson
367ae771770SStanislav Sedov if (IS_DCE_STYLE(ctx)) {
368ae771770SStanislav Sedov padlength = 0;
369ae771770SStanislav Sedov datalen = input_message_buffer->length;
370ae771770SStanislav Sedov len = 34 + 8;
371ae771770SStanislav Sedov _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
372ae771770SStanislav Sedov total_len += datalen;
373ae771770SStanislav Sedov datalen += 8;
374ae771770SStanislav Sedov } else {
375c19800e8SDoug Rabson padlength = 8 - (input_message_buffer->length % 8);
376c19800e8SDoug Rabson datalen = input_message_buffer->length + padlength + 8;
377c19800e8SDoug Rabson len = datalen + 34;
378c19800e8SDoug Rabson _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
379ae771770SStanislav Sedov }
380c19800e8SDoug Rabson
381c19800e8SDoug Rabson output_message_buffer->length = total_len;
382c19800e8SDoug Rabson output_message_buffer->value = malloc (total_len);
383c19800e8SDoug Rabson if (output_message_buffer->value == NULL) {
384c19800e8SDoug Rabson output_message_buffer->length = 0;
385c19800e8SDoug Rabson *minor_status = ENOMEM;
386c19800e8SDoug Rabson return GSS_S_FAILURE;
387c19800e8SDoug Rabson }
388c19800e8SDoug Rabson
389c19800e8SDoug Rabson p = _gsskrb5_make_header(output_message_buffer->value,
390c19800e8SDoug Rabson len,
391c19800e8SDoug Rabson "\x02\x01", /* TOK_ID */
392c19800e8SDoug Rabson GSS_KRB5_MECHANISM);
393c19800e8SDoug Rabson
394c19800e8SDoug Rabson /* SGN_ALG */
395c19800e8SDoug Rabson memcpy (p, "\x04\x00", 2); /* HMAC SHA1 DES3-KD */
396c19800e8SDoug Rabson p += 2;
397c19800e8SDoug Rabson /* SEAL_ALG */
398c19800e8SDoug Rabson if(conf_req_flag)
399c19800e8SDoug Rabson memcpy (p, "\x02\x00", 2); /* DES3-KD */
400c19800e8SDoug Rabson else
401c19800e8SDoug Rabson memcpy (p, "\xff\xff", 2);
402c19800e8SDoug Rabson p += 2;
403c19800e8SDoug Rabson /* Filler */
404c19800e8SDoug Rabson memcpy (p, "\xff\xff", 2);
405c19800e8SDoug Rabson p += 2;
406c19800e8SDoug Rabson
407c19800e8SDoug Rabson /* calculate checksum (the above + confounder + data + pad) */
408c19800e8SDoug Rabson
409c19800e8SDoug Rabson memcpy (p + 20, p - 8, 8);
410c19800e8SDoug Rabson krb5_generate_random_block(p + 28, 8);
411c19800e8SDoug Rabson memcpy (p + 28 + 8, input_message_buffer->value,
412c19800e8SDoug Rabson input_message_buffer->length);
413c19800e8SDoug Rabson memset (p + 28 + 8 + input_message_buffer->length, padlength, padlength);
414c19800e8SDoug Rabson
415c19800e8SDoug Rabson ret = krb5_crypto_init(context, key, 0, &crypto);
416c19800e8SDoug Rabson if (ret) {
417c19800e8SDoug Rabson free (output_message_buffer->value);
418c19800e8SDoug Rabson output_message_buffer->length = 0;
419c19800e8SDoug Rabson output_message_buffer->value = NULL;
420c19800e8SDoug Rabson *minor_status = ret;
421c19800e8SDoug Rabson return GSS_S_FAILURE;
422c19800e8SDoug Rabson }
423c19800e8SDoug Rabson
424c19800e8SDoug Rabson ret = krb5_create_checksum (context,
425c19800e8SDoug Rabson crypto,
426c19800e8SDoug Rabson KRB5_KU_USAGE_SIGN,
427c19800e8SDoug Rabson 0,
428c19800e8SDoug Rabson p + 20,
429c19800e8SDoug Rabson datalen + 8,
430c19800e8SDoug Rabson &cksum);
431c19800e8SDoug Rabson krb5_crypto_destroy (context, crypto);
432c19800e8SDoug Rabson if (ret) {
433c19800e8SDoug Rabson free (output_message_buffer->value);
434c19800e8SDoug Rabson output_message_buffer->length = 0;
435c19800e8SDoug Rabson output_message_buffer->value = NULL;
436c19800e8SDoug Rabson *minor_status = ret;
437c19800e8SDoug Rabson return GSS_S_FAILURE;
438c19800e8SDoug Rabson }
439c19800e8SDoug Rabson
440c19800e8SDoug Rabson /* zero out SND_SEQ + SGN_CKSUM in case */
441c19800e8SDoug Rabson memset (p, 0, 28);
442c19800e8SDoug Rabson
443c19800e8SDoug Rabson memcpy (p + 8, cksum.checksum.data, cksum.checksum.length);
444c19800e8SDoug Rabson free_Checksum (&cksum);
445c19800e8SDoug Rabson
446c19800e8SDoug Rabson HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
447c19800e8SDoug Rabson /* sequence number */
448c19800e8SDoug Rabson krb5_auth_con_getlocalseqnumber (context,
449c19800e8SDoug Rabson ctx->auth_context,
450c19800e8SDoug Rabson &seq_number);
451c19800e8SDoug Rabson
452c19800e8SDoug Rabson seq[0] = (seq_number >> 0) & 0xFF;
453c19800e8SDoug Rabson seq[1] = (seq_number >> 8) & 0xFF;
454c19800e8SDoug Rabson seq[2] = (seq_number >> 16) & 0xFF;
455c19800e8SDoug Rabson seq[3] = (seq_number >> 24) & 0xFF;
456c19800e8SDoug Rabson memset (seq + 4,
457c19800e8SDoug Rabson (ctx->more_flags & LOCAL) ? 0 : 0xFF,
458c19800e8SDoug Rabson 4);
459c19800e8SDoug Rabson
460c19800e8SDoug Rabson
461c19800e8SDoug Rabson ret = krb5_crypto_init(context, key, ETYPE_DES3_CBC_NONE,
462c19800e8SDoug Rabson &crypto);
463c19800e8SDoug Rabson if (ret) {
464c19800e8SDoug Rabson free (output_message_buffer->value);
465c19800e8SDoug Rabson output_message_buffer->length = 0;
466c19800e8SDoug Rabson output_message_buffer->value = NULL;
467c19800e8SDoug Rabson *minor_status = ret;
468c19800e8SDoug Rabson return GSS_S_FAILURE;
469c19800e8SDoug Rabson }
470c19800e8SDoug Rabson
471c19800e8SDoug Rabson {
472c19800e8SDoug Rabson DES_cblock ivec;
473c19800e8SDoug Rabson
474c19800e8SDoug Rabson memcpy (&ivec, p + 8, 8);
475c19800e8SDoug Rabson ret = krb5_encrypt_ivec (context,
476c19800e8SDoug Rabson crypto,
477c19800e8SDoug Rabson KRB5_KU_USAGE_SEQ,
478c19800e8SDoug Rabson seq, 8, &encdata,
479c19800e8SDoug Rabson &ivec);
480c19800e8SDoug Rabson }
481c19800e8SDoug Rabson krb5_crypto_destroy (context, crypto);
482c19800e8SDoug Rabson if (ret) {
483c19800e8SDoug Rabson free (output_message_buffer->value);
484c19800e8SDoug Rabson output_message_buffer->length = 0;
485c19800e8SDoug Rabson output_message_buffer->value = NULL;
486c19800e8SDoug Rabson *minor_status = ret;
487c19800e8SDoug Rabson return GSS_S_FAILURE;
488c19800e8SDoug Rabson }
489c19800e8SDoug Rabson
490c19800e8SDoug Rabson assert (encdata.length == 8);
491c19800e8SDoug Rabson
492c19800e8SDoug Rabson memcpy (p, encdata.data, encdata.length);
493c19800e8SDoug Rabson krb5_data_free (&encdata);
494c19800e8SDoug Rabson
495c19800e8SDoug Rabson krb5_auth_con_setlocalseqnumber (context,
496c19800e8SDoug Rabson ctx->auth_context,
497c19800e8SDoug Rabson ++seq_number);
498c19800e8SDoug Rabson HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
499c19800e8SDoug Rabson
500c19800e8SDoug Rabson /* encrypt the data */
501c19800e8SDoug Rabson p += 28;
502c19800e8SDoug Rabson
503c19800e8SDoug Rabson if(conf_req_flag) {
504c19800e8SDoug Rabson krb5_data tmp;
505c19800e8SDoug Rabson
506c19800e8SDoug Rabson ret = krb5_crypto_init(context, key,
507c19800e8SDoug Rabson ETYPE_DES3_CBC_NONE, &crypto);
508c19800e8SDoug Rabson if (ret) {
509c19800e8SDoug Rabson free (output_message_buffer->value);
510c19800e8SDoug Rabson output_message_buffer->length = 0;
511c19800e8SDoug Rabson output_message_buffer->value = NULL;
512c19800e8SDoug Rabson *minor_status = ret;
513c19800e8SDoug Rabson return GSS_S_FAILURE;
514c19800e8SDoug Rabson }
515c19800e8SDoug Rabson ret = krb5_encrypt(context, crypto, KRB5_KU_USAGE_SEAL,
516c19800e8SDoug Rabson p, datalen, &tmp);
517c19800e8SDoug Rabson krb5_crypto_destroy(context, crypto);
518c19800e8SDoug Rabson if (ret) {
519c19800e8SDoug Rabson free (output_message_buffer->value);
520c19800e8SDoug Rabson output_message_buffer->length = 0;
521c19800e8SDoug Rabson output_message_buffer->value = NULL;
522c19800e8SDoug Rabson *minor_status = ret;
523c19800e8SDoug Rabson return GSS_S_FAILURE;
524c19800e8SDoug Rabson }
525c19800e8SDoug Rabson assert (tmp.length == datalen);
526c19800e8SDoug Rabson
527c19800e8SDoug Rabson memcpy (p, tmp.data, datalen);
528c19800e8SDoug Rabson krb5_data_free(&tmp);
529c19800e8SDoug Rabson }
530c19800e8SDoug Rabson if(conf_state != NULL)
531c19800e8SDoug Rabson *conf_state = conf_req_flag;
532c19800e8SDoug Rabson *minor_status = 0;
533c19800e8SDoug Rabson return GSS_S_COMPLETE;
534c19800e8SDoug Rabson }
535c19800e8SDoug Rabson
536ae771770SStanislav Sedov OM_uint32 GSSAPI_CALLCONV
_gsskrb5_wrap(OM_uint32 * minor_status,const gss_ctx_id_t context_handle,int conf_req_flag,gss_qop_t qop_req,const gss_buffer_t input_message_buffer,int * conf_state,gss_buffer_t output_message_buffer)537ae771770SStanislav Sedov _gsskrb5_wrap
538c19800e8SDoug Rabson (OM_uint32 * minor_status,
539c19800e8SDoug Rabson const gss_ctx_id_t context_handle,
540c19800e8SDoug Rabson int conf_req_flag,
541c19800e8SDoug Rabson gss_qop_t qop_req,
542c19800e8SDoug Rabson const gss_buffer_t input_message_buffer,
543c19800e8SDoug Rabson int * conf_state,
544c19800e8SDoug Rabson gss_buffer_t output_message_buffer
545c19800e8SDoug Rabson )
546c19800e8SDoug Rabson {
547c19800e8SDoug Rabson krb5_context context;
548c19800e8SDoug Rabson krb5_keyblock *key;
549c19800e8SDoug Rabson OM_uint32 ret;
550c19800e8SDoug Rabson krb5_keytype keytype;
551c19800e8SDoug Rabson const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
552c19800e8SDoug Rabson
553ae771770SStanislav Sedov output_message_buffer->value = NULL;
554ae771770SStanislav Sedov output_message_buffer->length = 0;
555ae771770SStanislav Sedov
556c19800e8SDoug Rabson GSSAPI_KRB5_INIT (&context);
557c19800e8SDoug Rabson
558ae771770SStanislav Sedov if (ctx->more_flags & IS_CFX)
559ae771770SStanislav Sedov return _gssapi_wrap_cfx (minor_status, ctx, context, conf_req_flag,
560ae771770SStanislav Sedov input_message_buffer, conf_state,
561ae771770SStanislav Sedov output_message_buffer);
562ae771770SStanislav Sedov
563c19800e8SDoug Rabson HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
564c19800e8SDoug Rabson ret = _gsskrb5i_get_token_key(ctx, context, &key);
565c19800e8SDoug Rabson HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
566c19800e8SDoug Rabson if (ret) {
567c19800e8SDoug Rabson *minor_status = ret;
568c19800e8SDoug Rabson return GSS_S_FAILURE;
569c19800e8SDoug Rabson }
570c19800e8SDoug Rabson krb5_enctype_to_keytype (context, key->keytype, &keytype);
571c19800e8SDoug Rabson
572c19800e8SDoug Rabson switch (keytype) {
573c19800e8SDoug Rabson case KEYTYPE_DES :
574ae771770SStanislav Sedov #ifdef HEIM_WEAK_CRYPTO
575c19800e8SDoug Rabson ret = wrap_des (minor_status, ctx, context, conf_req_flag,
576c19800e8SDoug Rabson qop_req, input_message_buffer, conf_state,
577c19800e8SDoug Rabson output_message_buffer, key);
578ae771770SStanislav Sedov #else
579ae771770SStanislav Sedov ret = GSS_S_FAILURE;
580ae771770SStanislav Sedov #endif
581c19800e8SDoug Rabson break;
582c19800e8SDoug Rabson case KEYTYPE_DES3 :
583c19800e8SDoug Rabson ret = wrap_des3 (minor_status, ctx, context, conf_req_flag,
584c19800e8SDoug Rabson qop_req, input_message_buffer, conf_state,
585c19800e8SDoug Rabson output_message_buffer, key);
586c19800e8SDoug Rabson break;
587c19800e8SDoug Rabson case KEYTYPE_ARCFOUR:
588c19800e8SDoug Rabson case KEYTYPE_ARCFOUR_56:
589c19800e8SDoug Rabson ret = _gssapi_wrap_arcfour (minor_status, ctx, context, conf_req_flag,
590c19800e8SDoug Rabson qop_req, input_message_buffer, conf_state,
591c19800e8SDoug Rabson output_message_buffer, key);
592c19800e8SDoug Rabson break;
593c19800e8SDoug Rabson default :
594ae771770SStanislav Sedov abort();
595c19800e8SDoug Rabson break;
596c19800e8SDoug Rabson }
597c19800e8SDoug Rabson krb5_free_keyblock (context, key);
598c19800e8SDoug Rabson return ret;
599c19800e8SDoug Rabson }
600