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