1*afab4e30Schristos /* $NetBSD: arcfour.c,v 1.6 2023/06/19 21:41:43 christos Exp $ */
2ca1c9b0cSelric
3ca1c9b0cSelric /*
4ca1c9b0cSelric * Copyright (c) 2003 - 2006 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 * Implements draft-brezak-win2k-krb-rc4-hmac-04.txt
40ca1c9b0cSelric *
41ca1c9b0cSelric * The arcfour message have the following formats:
42ca1c9b0cSelric *
43ca1c9b0cSelric * MIC token
44ca1c9b0cSelric * TOK_ID[2] = 01 01
45ca1c9b0cSelric * SGN_ALG[2] = 11 00
46ca1c9b0cSelric * Filler[4]
47ca1c9b0cSelric * SND_SEQ[8]
48ca1c9b0cSelric * SGN_CKSUM[8]
49ca1c9b0cSelric *
50ca1c9b0cSelric * WRAP token
51ca1c9b0cSelric * TOK_ID[2] = 02 01
52ca1c9b0cSelric * SGN_ALG[2];
53ca1c9b0cSelric * SEAL_ALG[2]
54ca1c9b0cSelric * Filler[2]
55ca1c9b0cSelric * SND_SEQ[2]
56ca1c9b0cSelric * SGN_CKSUM[8]
57ca1c9b0cSelric * Confounder[8]
58ca1c9b0cSelric */
59ca1c9b0cSelric
60ca1c9b0cSelric /*
61ca1c9b0cSelric * WRAP in DCE-style have a fixed size header, the oid and length over
62ca1c9b0cSelric * the WRAP header is a total of
63ca1c9b0cSelric * GSS_ARCFOUR_WRAP_TOKEN_DCE_DER_HEADER_SIZE +
64ca1c9b0cSelric * GSS_ARCFOUR_WRAP_TOKEN_SIZE byte (ie total of 45 bytes overhead,
65ca1c9b0cSelric * remember the 2 bytes from APPL [0] SEQ).
66ca1c9b0cSelric */
67ca1c9b0cSelric
68ca1c9b0cSelric #define GSS_ARCFOUR_WRAP_TOKEN_SIZE 32
69ca1c9b0cSelric #define GSS_ARCFOUR_WRAP_TOKEN_DCE_DER_HEADER_SIZE 13
70ca1c9b0cSelric
71ca1c9b0cSelric
72ca1c9b0cSelric static krb5_error_code
arcfour_mic_key(krb5_context context,krb5_keyblock * key,const void * cksum_data,size_t cksum_size,void * key6_data,size_t key6_size)73ca1c9b0cSelric arcfour_mic_key(krb5_context context, krb5_keyblock *key,
74b9d004c6Schristos const void *cksum_data, size_t cksum_size,
75ca1c9b0cSelric void *key6_data, size_t key6_size)
76ca1c9b0cSelric {
77ca1c9b0cSelric krb5_error_code ret;
78ca1c9b0cSelric
79ca1c9b0cSelric Checksum cksum_k5;
80ca1c9b0cSelric krb5_keyblock key5;
81ca1c9b0cSelric char k5_data[16];
82ca1c9b0cSelric
83ca1c9b0cSelric Checksum cksum_k6;
84ca1c9b0cSelric
85ca1c9b0cSelric char T[4];
86ca1c9b0cSelric
87ca1c9b0cSelric memset(T, 0, 4);
88ca1c9b0cSelric cksum_k5.checksum.data = k5_data;
89ca1c9b0cSelric cksum_k5.checksum.length = sizeof(k5_data);
90ca1c9b0cSelric
91b9d004c6Schristos if (key->keytype == KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56) {
92ca1c9b0cSelric char L40[14] = "fortybits";
93ca1c9b0cSelric
94ca1c9b0cSelric memcpy(L40 + 10, T, sizeof(T));
95ca1c9b0cSelric ret = krb5_hmac(context, CKSUMTYPE_RSA_MD5,
96ca1c9b0cSelric L40, 14, 0, key, &cksum_k5);
97ca1c9b0cSelric memset(&k5_data[7], 0xAB, 9);
98ca1c9b0cSelric } else {
99ca1c9b0cSelric ret = krb5_hmac(context, CKSUMTYPE_RSA_MD5,
100ca1c9b0cSelric T, 4, 0, key, &cksum_k5);
101ca1c9b0cSelric }
102ca1c9b0cSelric if (ret)
103ca1c9b0cSelric return ret;
104ca1c9b0cSelric
105b9d004c6Schristos key5.keytype = KRB5_ENCTYPE_ARCFOUR_HMAC_MD5;
106ca1c9b0cSelric key5.keyvalue = cksum_k5.checksum;
107ca1c9b0cSelric
108ca1c9b0cSelric cksum_k6.checksum.data = key6_data;
109ca1c9b0cSelric cksum_k6.checksum.length = key6_size;
110ca1c9b0cSelric
111ca1c9b0cSelric return krb5_hmac(context, CKSUMTYPE_RSA_MD5,
112ca1c9b0cSelric cksum_data, cksum_size, 0, &key5, &cksum_k6);
113ca1c9b0cSelric }
114ca1c9b0cSelric
115ca1c9b0cSelric
116ca1c9b0cSelric static krb5_error_code
arcfour_mic_cksum_iov(krb5_context context,krb5_keyblock * key,unsigned usage,u_char * sgn_cksum,size_t sgn_cksum_sz,const u_char * v1,size_t l1,const void * v2,size_t l2,const gss_iov_buffer_desc * iov,int iov_count,const gss_iov_buffer_desc * padding)117b9d004c6Schristos arcfour_mic_cksum_iov(krb5_context context,
118ca1c9b0cSelric krb5_keyblock *key, unsigned usage,
119ca1c9b0cSelric u_char *sgn_cksum, size_t sgn_cksum_sz,
120ca1c9b0cSelric const u_char *v1, size_t l1,
121ca1c9b0cSelric const void *v2, size_t l2,
122b9d004c6Schristos const gss_iov_buffer_desc *iov,
123b9d004c6Schristos int iov_count,
124b9d004c6Schristos const gss_iov_buffer_desc *padding)
125ca1c9b0cSelric {
126ca1c9b0cSelric Checksum CKSUM;
127ca1c9b0cSelric u_char *ptr;
128ca1c9b0cSelric size_t len;
129b9d004c6Schristos size_t ofs = 0;
130b9d004c6Schristos int i;
131ca1c9b0cSelric krb5_crypto crypto;
132ca1c9b0cSelric krb5_error_code ret;
133ca1c9b0cSelric
134ca1c9b0cSelric assert(sgn_cksum_sz == 8);
135ca1c9b0cSelric
136b9d004c6Schristos len = l1 + l2;
137b9d004c6Schristos
138b9d004c6Schristos for (i=0; i < iov_count; i++) {
139b9d004c6Schristos switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
140b9d004c6Schristos case GSS_IOV_BUFFER_TYPE_DATA:
141b9d004c6Schristos case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
142b9d004c6Schristos break;
143b9d004c6Schristos default:
144b9d004c6Schristos continue;
145b9d004c6Schristos }
146b9d004c6Schristos
147b9d004c6Schristos len += iov[i].buffer.length;
148b9d004c6Schristos }
149b9d004c6Schristos
150b9d004c6Schristos if (padding) {
151b9d004c6Schristos len += padding->buffer.length;
152b9d004c6Schristos }
153ca1c9b0cSelric
154ca1c9b0cSelric ptr = malloc(len);
155ca1c9b0cSelric if (ptr == NULL)
156ca1c9b0cSelric return ENOMEM;
157ca1c9b0cSelric
158b9d004c6Schristos memcpy(ptr + ofs, v1, l1);
159b9d004c6Schristos ofs += l1;
160b9d004c6Schristos memcpy(ptr + ofs, v2, l2);
161b9d004c6Schristos ofs += l2;
162b9d004c6Schristos
163b9d004c6Schristos for (i=0; i < iov_count; i++) {
164b9d004c6Schristos switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
165b9d004c6Schristos case GSS_IOV_BUFFER_TYPE_DATA:
166b9d004c6Schristos case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
167b9d004c6Schristos break;
168b9d004c6Schristos default:
169b9d004c6Schristos continue;
170b9d004c6Schristos }
171b9d004c6Schristos
172b9d004c6Schristos memcpy(ptr + ofs,
173b9d004c6Schristos iov[i].buffer.value,
174b9d004c6Schristos iov[i].buffer.length);
175b9d004c6Schristos ofs += iov[i].buffer.length;
176b9d004c6Schristos }
177b9d004c6Schristos
178b9d004c6Schristos if (padding) {
179b9d004c6Schristos memcpy(ptr + ofs,
180b9d004c6Schristos padding->buffer.value,
181b9d004c6Schristos padding->buffer.length);
182*afab4e30Schristos /* ofs += padding->buffer.length; */
183b9d004c6Schristos }
184ca1c9b0cSelric
185ca1c9b0cSelric ret = krb5_crypto_init(context, key, 0, &crypto);
186ca1c9b0cSelric if (ret) {
187ca1c9b0cSelric free(ptr);
188ca1c9b0cSelric return ret;
189ca1c9b0cSelric }
190ca1c9b0cSelric
191ca1c9b0cSelric ret = krb5_create_checksum(context,
192ca1c9b0cSelric crypto,
193ca1c9b0cSelric usage,
194ca1c9b0cSelric 0,
195ca1c9b0cSelric ptr, len,
196ca1c9b0cSelric &CKSUM);
197b9d004c6Schristos memset(ptr, 0, len);
198ca1c9b0cSelric free(ptr);
199ca1c9b0cSelric if (ret == 0) {
200ca1c9b0cSelric memcpy(sgn_cksum, CKSUM.checksum.data, sgn_cksum_sz);
201ca1c9b0cSelric free_Checksum(&CKSUM);
202ca1c9b0cSelric }
203ca1c9b0cSelric krb5_crypto_destroy(context, crypto);
204ca1c9b0cSelric
205ca1c9b0cSelric return ret;
206ca1c9b0cSelric }
207ca1c9b0cSelric
208b9d004c6Schristos static krb5_error_code
arcfour_mic_cksum(krb5_context context,krb5_keyblock * key,unsigned usage,u_char * sgn_cksum,size_t sgn_cksum_sz,const u_char * v1,size_t l1,const void * v2,size_t l2,const void * v3,size_t l3)209b9d004c6Schristos arcfour_mic_cksum(krb5_context context,
210b9d004c6Schristos krb5_keyblock *key, unsigned usage,
211b9d004c6Schristos u_char *sgn_cksum, size_t sgn_cksum_sz,
212b9d004c6Schristos const u_char *v1, size_t l1,
213b9d004c6Schristos const void *v2, size_t l2,
214b9d004c6Schristos const void *v3, size_t l3)
215b9d004c6Schristos {
216b9d004c6Schristos gss_iov_buffer_desc iov;
217b9d004c6Schristos
218b9d004c6Schristos iov.type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
219b9d004c6Schristos iov.buffer.value = rk_UNCONST(v3);
220b9d004c6Schristos iov.buffer.length = l3;
221b9d004c6Schristos
222b9d004c6Schristos return arcfour_mic_cksum_iov(context, key, usage,
223b9d004c6Schristos sgn_cksum, sgn_cksum_sz,
224b9d004c6Schristos v1, l1, v2, l2,
225b9d004c6Schristos &iov, 1, NULL);
226b9d004c6Schristos }
227b9d004c6Schristos
228ca1c9b0cSelric
229ca1c9b0cSelric OM_uint32
_gssapi_get_mic_arcfour(OM_uint32 * minor_status,const gsskrb5_ctx context_handle,krb5_context context,gss_qop_t qop_req,const gss_buffer_t message_buffer,gss_buffer_t message_token,krb5_keyblock * key)230ca1c9b0cSelric _gssapi_get_mic_arcfour(OM_uint32 * minor_status,
231ca1c9b0cSelric const gsskrb5_ctx context_handle,
232ca1c9b0cSelric krb5_context context,
233ca1c9b0cSelric gss_qop_t qop_req,
234ca1c9b0cSelric const gss_buffer_t message_buffer,
235ca1c9b0cSelric gss_buffer_t message_token,
236ca1c9b0cSelric krb5_keyblock *key)
237ca1c9b0cSelric {
238ca1c9b0cSelric krb5_error_code ret;
239ca1c9b0cSelric int32_t seq_number;
240ca1c9b0cSelric size_t len, total_len;
241ca1c9b0cSelric u_char k6_data[16], *p0, *p;
2426680b65dSchristos EVP_CIPHER_CTX *rc4_key;
243ca1c9b0cSelric
244ca1c9b0cSelric _gsskrb5_encap_length (22, &len, &total_len, GSS_KRB5_MECHANISM);
245ca1c9b0cSelric
246ca1c9b0cSelric message_token->length = total_len;
247ca1c9b0cSelric message_token->value = malloc (total_len);
248ca1c9b0cSelric if (message_token->value == NULL) {
249ca1c9b0cSelric *minor_status = ENOMEM;
250ca1c9b0cSelric return GSS_S_FAILURE;
251ca1c9b0cSelric }
252ca1c9b0cSelric
253ca1c9b0cSelric p0 = _gssapi_make_mech_header(message_token->value,
254ca1c9b0cSelric len,
255ca1c9b0cSelric GSS_KRB5_MECHANISM);
256ca1c9b0cSelric p = p0;
257ca1c9b0cSelric
258ca1c9b0cSelric *p++ = 0x01; /* TOK_ID */
259ca1c9b0cSelric *p++ = 0x01;
260ca1c9b0cSelric *p++ = 0x11; /* SGN_ALG */
261ca1c9b0cSelric *p++ = 0x00;
262ca1c9b0cSelric *p++ = 0xff; /* Filler */
263ca1c9b0cSelric *p++ = 0xff;
264ca1c9b0cSelric *p++ = 0xff;
265ca1c9b0cSelric *p++ = 0xff;
266ca1c9b0cSelric
267ca1c9b0cSelric p = NULL;
268ca1c9b0cSelric
269ca1c9b0cSelric ret = arcfour_mic_cksum(context,
270ca1c9b0cSelric key, KRB5_KU_USAGE_SIGN,
271ca1c9b0cSelric p0 + 16, 8, /* SGN_CKSUM */
272ca1c9b0cSelric p0, 8, /* TOK_ID, SGN_ALG, Filer */
273ca1c9b0cSelric message_buffer->value, message_buffer->length,
274ca1c9b0cSelric NULL, 0);
275ca1c9b0cSelric if (ret) {
276ca1c9b0cSelric _gsskrb5_release_buffer(minor_status, message_token);
277ca1c9b0cSelric *minor_status = ret;
278ca1c9b0cSelric return GSS_S_FAILURE;
279ca1c9b0cSelric }
280ca1c9b0cSelric
281ca1c9b0cSelric ret = arcfour_mic_key(context, key,
282ca1c9b0cSelric p0 + 16, 8, /* SGN_CKSUM */
283ca1c9b0cSelric k6_data, sizeof(k6_data));
284ca1c9b0cSelric if (ret) {
285ca1c9b0cSelric _gsskrb5_release_buffer(minor_status, message_token);
286ca1c9b0cSelric *minor_status = ret;
287ca1c9b0cSelric return GSS_S_FAILURE;
288ca1c9b0cSelric }
289ca1c9b0cSelric
290ca1c9b0cSelric HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
291ca1c9b0cSelric krb5_auth_con_getlocalseqnumber (context,
292ca1c9b0cSelric context_handle->auth_context,
293ca1c9b0cSelric &seq_number);
294ca1c9b0cSelric p = p0 + 8; /* SND_SEQ */
295ca1c9b0cSelric _gsskrb5_encode_be_om_uint32(seq_number, p);
296ca1c9b0cSelric
297ca1c9b0cSelric krb5_auth_con_setlocalseqnumber (context,
298ca1c9b0cSelric context_handle->auth_context,
299ca1c9b0cSelric ++seq_number);
300ca1c9b0cSelric HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
301ca1c9b0cSelric
302ca1c9b0cSelric memset (p + 4, (context_handle->more_flags & LOCAL) ? 0 : 0xff, 4);
303ca1c9b0cSelric
3046680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
3056680b65dSchristos EVP_CIPHER_CTX rc4_keys;
3066680b65dSchristos rc4_key = &rc4_keys;
3076680b65dSchristos EVP_CIPHER_CTX_init(rc4_key);
3086680b65dSchristos #else
3096680b65dSchristos rc4_key = EVP_CIPHER_CTX_new();
3106680b65dSchristos #endif
3117b2118deSchristos if (!EVP_CipherInit_ex(rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1)) {
3127b2118deSchristos *minor_status = EINVAL;
3137b2118deSchristos return GSS_S_FAILURE;
3147b2118deSchristos }
3157b2118deSchristos
3166680b65dSchristos EVP_Cipher(rc4_key, p, p, 8);
3176680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
3186680b65dSchristos EVP_CIPHER_CTX_cleanup(rc4_key);
3196680b65dSchristos #else
3206680b65dSchristos EVP_CIPHER_CTX_free(rc4_key);
3216680b65dSchristos #endif
322ca1c9b0cSelric
323241bea01Schristos memset_s(k6_data, sizeof(k6_data), 0, sizeof(k6_data));
324ca1c9b0cSelric
325ca1c9b0cSelric *minor_status = 0;
326ca1c9b0cSelric return GSS_S_COMPLETE;
327ca1c9b0cSelric }
328ca1c9b0cSelric
329ca1c9b0cSelric
330ca1c9b0cSelric OM_uint32
_gssapi_verify_mic_arcfour(OM_uint32 * minor_status,const gsskrb5_ctx context_handle,krb5_context context,const gss_buffer_t message_buffer,const gss_buffer_t token_buffer,gss_qop_t * qop_state,krb5_keyblock * key,const char * type)331ca1c9b0cSelric _gssapi_verify_mic_arcfour(OM_uint32 * minor_status,
332ca1c9b0cSelric const gsskrb5_ctx context_handle,
333ca1c9b0cSelric krb5_context context,
334ca1c9b0cSelric const gss_buffer_t message_buffer,
335ca1c9b0cSelric const gss_buffer_t token_buffer,
336ca1c9b0cSelric gss_qop_t * qop_state,
337ca1c9b0cSelric krb5_keyblock *key,
3384f77a458Spettai const char *type)
339ca1c9b0cSelric {
340ca1c9b0cSelric krb5_error_code ret;
341ca1c9b0cSelric uint32_t seq_number;
342ca1c9b0cSelric OM_uint32 omret;
343ca1c9b0cSelric u_char SND_SEQ[8], cksum_data[8], *p;
344ca1c9b0cSelric char k6_data[16];
345ca1c9b0cSelric int cmp;
346ca1c9b0cSelric
347ca1c9b0cSelric if (qop_state)
348ca1c9b0cSelric *qop_state = 0;
349ca1c9b0cSelric
350ca1c9b0cSelric p = token_buffer->value;
351ca1c9b0cSelric omret = _gsskrb5_verify_header (&p,
352ca1c9b0cSelric token_buffer->length,
3534f77a458Spettai type,
354ca1c9b0cSelric GSS_KRB5_MECHANISM);
355ca1c9b0cSelric if (omret)
356ca1c9b0cSelric return omret;
357ca1c9b0cSelric
358ca1c9b0cSelric if (memcmp(p, "\x11\x00", 2) != 0) /* SGN_ALG = HMAC MD5 ARCFOUR */
359ca1c9b0cSelric return GSS_S_BAD_SIG;
360ca1c9b0cSelric p += 2;
361ca1c9b0cSelric if (memcmp (p, "\xff\xff\xff\xff", 4) != 0)
362ca1c9b0cSelric return GSS_S_BAD_MIC;
363ca1c9b0cSelric p += 4;
364ca1c9b0cSelric
365ca1c9b0cSelric ret = arcfour_mic_cksum(context,
366ca1c9b0cSelric key, KRB5_KU_USAGE_SIGN,
367ca1c9b0cSelric cksum_data, sizeof(cksum_data),
368ca1c9b0cSelric p - 8, 8,
369ca1c9b0cSelric message_buffer->value, message_buffer->length,
370ca1c9b0cSelric NULL, 0);
371ca1c9b0cSelric if (ret) {
372ca1c9b0cSelric *minor_status = ret;
373ca1c9b0cSelric return GSS_S_FAILURE;
374ca1c9b0cSelric }
375ca1c9b0cSelric
376ca1c9b0cSelric ret = arcfour_mic_key(context, key,
377ca1c9b0cSelric cksum_data, sizeof(cksum_data),
378ca1c9b0cSelric k6_data, sizeof(k6_data));
379ca1c9b0cSelric if (ret) {
380ca1c9b0cSelric *minor_status = ret;
381ca1c9b0cSelric return GSS_S_FAILURE;
382ca1c9b0cSelric }
383ca1c9b0cSelric
384*afab4e30Schristos cmp = (ct_memcmp(cksum_data, p + 8, 8) == 0);
385ca1c9b0cSelric if (cmp) {
386ca1c9b0cSelric *minor_status = 0;
387ca1c9b0cSelric return GSS_S_BAD_MIC;
388ca1c9b0cSelric }
389ca1c9b0cSelric
390ca1c9b0cSelric {
3916680b65dSchristos EVP_CIPHER_CTX *rc4_key;
3926680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
3936680b65dSchristos EVP_CIPHER_CTX rc4_keys;
3946680b65dSchristos rc4_key = &rc4_keys;
3956680b65dSchristos EVP_CIPHER_CTX_init(rc4_key);
3966680b65dSchristos #else
3976680b65dSchristos rc4_key = EVP_CIPHER_CTX_new();
3986680b65dSchristos #endif
399ca1c9b0cSelric
4007b2118deSchristos if (!EVP_CipherInit_ex(rc4_key, EVP_rc4(), NULL, (void *)k6_data, NULL,
4017b2118deSchristos 0)) {
4027b2118deSchristos *minor_status = EINVAL;
4037b2118deSchristos return GSS_S_FAILURE;
4047b2118deSchristos }
4056680b65dSchristos EVP_Cipher(rc4_key, SND_SEQ, p, 8);
4066680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
4076680b65dSchristos EVP_CIPHER_CTX_cleanup(rc4_key);
4086680b65dSchristos #else
4096680b65dSchristos EVP_CIPHER_CTX_free(rc4_key);
4106680b65dSchristos #endif
411ca1c9b0cSelric
412241bea01Schristos memset_s(k6_data, sizeof(k6_data), 0, sizeof(k6_data));
413ca1c9b0cSelric }
414ca1c9b0cSelric
415ca1c9b0cSelric _gsskrb5_decode_be_om_uint32(SND_SEQ, &seq_number);
416ca1c9b0cSelric
417ca1c9b0cSelric if (context_handle->more_flags & LOCAL)
418*afab4e30Schristos cmp = (ct_memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4) != 0);
419ca1c9b0cSelric else
420*afab4e30Schristos cmp = (ct_memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4) != 0);
421ca1c9b0cSelric
422241bea01Schristos memset_s(SND_SEQ, sizeof(SND_SEQ), 0, sizeof(SND_SEQ));
423ca1c9b0cSelric if (cmp != 0) {
424ca1c9b0cSelric *minor_status = 0;
425ca1c9b0cSelric return GSS_S_BAD_MIC;
426ca1c9b0cSelric }
427ca1c9b0cSelric
428ca1c9b0cSelric HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
429ca1c9b0cSelric omret = _gssapi_msg_order_check(context_handle->order, seq_number);
430ca1c9b0cSelric HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
431ca1c9b0cSelric if (omret)
432ca1c9b0cSelric return omret;
433ca1c9b0cSelric
434ca1c9b0cSelric *minor_status = 0;
435ca1c9b0cSelric return GSS_S_COMPLETE;
436ca1c9b0cSelric }
437ca1c9b0cSelric
438ca1c9b0cSelric OM_uint32
_gssapi_wrap_arcfour(OM_uint32 * minor_status,const gsskrb5_ctx context_handle,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)439ca1c9b0cSelric _gssapi_wrap_arcfour(OM_uint32 * minor_status,
440ca1c9b0cSelric const gsskrb5_ctx context_handle,
441ca1c9b0cSelric krb5_context context,
442ca1c9b0cSelric int conf_req_flag,
443ca1c9b0cSelric gss_qop_t qop_req,
444ca1c9b0cSelric const gss_buffer_t input_message_buffer,
445ca1c9b0cSelric int * conf_state,
446ca1c9b0cSelric gss_buffer_t output_message_buffer,
447ca1c9b0cSelric krb5_keyblock *key)
448ca1c9b0cSelric {
449ca1c9b0cSelric u_char Klocaldata[16], k6_data[16], *p, *p0;
450ca1c9b0cSelric size_t len, total_len, datalen;
451ca1c9b0cSelric krb5_keyblock Klocal;
452ca1c9b0cSelric krb5_error_code ret;
453ca1c9b0cSelric int32_t seq_number;
454ca1c9b0cSelric
455ca1c9b0cSelric if (conf_state)
456ca1c9b0cSelric *conf_state = 0;
457ca1c9b0cSelric
458ca1c9b0cSelric datalen = input_message_buffer->length;
459ca1c9b0cSelric
460ca1c9b0cSelric if (IS_DCE_STYLE(context_handle)) {
461ca1c9b0cSelric len = GSS_ARCFOUR_WRAP_TOKEN_SIZE;
462ca1c9b0cSelric _gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
463ca1c9b0cSelric total_len += datalen;
464ca1c9b0cSelric } else {
465ca1c9b0cSelric datalen += 1; /* padding */
466ca1c9b0cSelric len = datalen + GSS_ARCFOUR_WRAP_TOKEN_SIZE;
467ca1c9b0cSelric _gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
468ca1c9b0cSelric }
469ca1c9b0cSelric
470ca1c9b0cSelric output_message_buffer->length = total_len;
471ca1c9b0cSelric output_message_buffer->value = malloc (total_len);
472ca1c9b0cSelric if (output_message_buffer->value == NULL) {
473ca1c9b0cSelric *minor_status = ENOMEM;
474ca1c9b0cSelric return GSS_S_FAILURE;
475ca1c9b0cSelric }
476ca1c9b0cSelric
477ca1c9b0cSelric p0 = _gssapi_make_mech_header(output_message_buffer->value,
478ca1c9b0cSelric len,
479ca1c9b0cSelric GSS_KRB5_MECHANISM);
480ca1c9b0cSelric p = p0;
481ca1c9b0cSelric
482ca1c9b0cSelric *p++ = 0x02; /* TOK_ID */
483ca1c9b0cSelric *p++ = 0x01;
484ca1c9b0cSelric *p++ = 0x11; /* SGN_ALG */
485ca1c9b0cSelric *p++ = 0x00;
486ca1c9b0cSelric if (conf_req_flag) {
487ca1c9b0cSelric *p++ = 0x10; /* SEAL_ALG */
488ca1c9b0cSelric *p++ = 0x00;
489ca1c9b0cSelric } else {
490ca1c9b0cSelric *p++ = 0xff; /* SEAL_ALG */
491ca1c9b0cSelric *p++ = 0xff;
492ca1c9b0cSelric }
493ca1c9b0cSelric *p++ = 0xff; /* Filler */
494ca1c9b0cSelric *p++ = 0xff;
495ca1c9b0cSelric
496ca1c9b0cSelric p = NULL;
497ca1c9b0cSelric
498ca1c9b0cSelric HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
499ca1c9b0cSelric krb5_auth_con_getlocalseqnumber (context,
500ca1c9b0cSelric context_handle->auth_context,
501ca1c9b0cSelric &seq_number);
502ca1c9b0cSelric
503ca1c9b0cSelric _gsskrb5_encode_be_om_uint32(seq_number, p0 + 8);
504ca1c9b0cSelric
505ca1c9b0cSelric krb5_auth_con_setlocalseqnumber (context,
506ca1c9b0cSelric context_handle->auth_context,
507ca1c9b0cSelric ++seq_number);
508ca1c9b0cSelric HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
509ca1c9b0cSelric
510ca1c9b0cSelric memset (p0 + 8 + 4,
511ca1c9b0cSelric (context_handle->more_flags & LOCAL) ? 0 : 0xff,
512ca1c9b0cSelric 4);
513ca1c9b0cSelric
514ca1c9b0cSelric krb5_generate_random_block(p0 + 24, 8); /* fill in Confounder */
515ca1c9b0cSelric
516ca1c9b0cSelric /* p points to data */
517ca1c9b0cSelric p = p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE;
518ca1c9b0cSelric memcpy(p, input_message_buffer->value, input_message_buffer->length);
519ca1c9b0cSelric
520ca1c9b0cSelric if (!IS_DCE_STYLE(context_handle))
521ca1c9b0cSelric p[input_message_buffer->length] = 1; /* padding */
522ca1c9b0cSelric
523ca1c9b0cSelric ret = arcfour_mic_cksum(context,
524ca1c9b0cSelric key, KRB5_KU_USAGE_SEAL,
525ca1c9b0cSelric p0 + 16, 8, /* SGN_CKSUM */
526ca1c9b0cSelric p0, 8, /* TOK_ID, SGN_ALG, SEAL_ALG, Filler */
527ca1c9b0cSelric p0 + 24, 8, /* Confounder */
528ca1c9b0cSelric p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE,
529ca1c9b0cSelric datalen);
530ca1c9b0cSelric if (ret) {
531ca1c9b0cSelric *minor_status = ret;
532ca1c9b0cSelric _gsskrb5_release_buffer(minor_status, output_message_buffer);
533ca1c9b0cSelric return GSS_S_FAILURE;
534ca1c9b0cSelric }
535ca1c9b0cSelric
536ca1c9b0cSelric {
537ca1c9b0cSelric int i;
538ca1c9b0cSelric
539ca1c9b0cSelric Klocal.keytype = key->keytype;
540ca1c9b0cSelric Klocal.keyvalue.data = Klocaldata;
541ca1c9b0cSelric Klocal.keyvalue.length = sizeof(Klocaldata);
542ca1c9b0cSelric
543ca1c9b0cSelric for (i = 0; i < 16; i++)
544ca1c9b0cSelric Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0;
545ca1c9b0cSelric }
546ca1c9b0cSelric ret = arcfour_mic_key(context, &Klocal,
547ca1c9b0cSelric p0 + 8, 4, /* SND_SEQ */
548ca1c9b0cSelric k6_data, sizeof(k6_data));
549241bea01Schristos memset_s(Klocaldata, sizeof(Klocaldata), 0, sizeof(Klocaldata));
550ca1c9b0cSelric if (ret) {
551ca1c9b0cSelric _gsskrb5_release_buffer(minor_status, output_message_buffer);
552ca1c9b0cSelric *minor_status = ret;
553ca1c9b0cSelric return GSS_S_FAILURE;
554ca1c9b0cSelric }
555ca1c9b0cSelric
556ca1c9b0cSelric
557ca1c9b0cSelric if(conf_req_flag) {
5586680b65dSchristos EVP_CIPHER_CTX *rc4_key;
5596680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
5606680b65dSchristos EVP_CIPHER_CTX rc4_keys;
5616680b65dSchristos rc4_key = &rc4_keys;
5626680b65dSchristos EVP_CIPHER_CTX_init(rc4_key);
5636680b65dSchristos #else
5646680b65dSchristos rc4_key = EVP_CIPHER_CTX_new();
5656680b65dSchristos #endif
566ca1c9b0cSelric
5676680b65dSchristos EVP_CIPHER_CTX_init(rc4_key);
5687b2118deSchristos if (!EVP_CipherInit_ex(rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1)) {
5697b2118deSchristos *minor_status = EINVAL;
5707b2118deSchristos return GSS_S_FAILURE;
5717b2118deSchristos }
5726680b65dSchristos EVP_Cipher(rc4_key, p0 + 24, p0 + 24, 8 + datalen);
5736680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
5746680b65dSchristos EVP_CIPHER_CTX_cleanup(rc4_key);
5756680b65dSchristos #else
5766680b65dSchristos EVP_CIPHER_CTX_free(rc4_key);
5776680b65dSchristos #endif
578ca1c9b0cSelric }
579241bea01Schristos memset_s(k6_data, sizeof(k6_data), 0, sizeof(k6_data));
580ca1c9b0cSelric
581ca1c9b0cSelric ret = arcfour_mic_key(context, key,
582ca1c9b0cSelric p0 + 16, 8, /* SGN_CKSUM */
583ca1c9b0cSelric k6_data, sizeof(k6_data));
584ca1c9b0cSelric if (ret) {
585ca1c9b0cSelric _gsskrb5_release_buffer(minor_status, output_message_buffer);
586ca1c9b0cSelric *minor_status = ret;
587ca1c9b0cSelric return GSS_S_FAILURE;
588ca1c9b0cSelric }
589ca1c9b0cSelric
590ca1c9b0cSelric {
5916680b65dSchristos EVP_CIPHER_CTX *rc4_key;
5926680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
5936680b65dSchristos EVP_CIPHER_CTX rc4_keys;
5946680b65dSchristos rc4_key = &rc4_keys;
5956680b65dSchristos EVP_CIPHER_CTX_init(rc4_key);
5966680b65dSchristos #else
5976680b65dSchristos rc4_key = EVP_CIPHER_CTX_new();
5986680b65dSchristos #endif
599ca1c9b0cSelric
6007b2118deSchristos if (!EVP_CipherInit_ex(rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1)) {
6017b2118deSchristos *minor_status = EINVAL;
6027b2118deSchristos return GSS_S_FAILURE;
6037b2118deSchristos }
6046680b65dSchristos EVP_Cipher(rc4_key, p0 + 8, p0 + 8 /* SND_SEQ */, 8);
6056680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
6066680b65dSchristos EVP_CIPHER_CTX_cleanup(rc4_key);
6076680b65dSchristos #else
6086680b65dSchristos EVP_CIPHER_CTX_free(rc4_key);
6096680b65dSchristos #endif
610241bea01Schristos memset_s(k6_data, sizeof(k6_data), 0, sizeof(k6_data));
611ca1c9b0cSelric }
612ca1c9b0cSelric
613ca1c9b0cSelric if (conf_state)
614ca1c9b0cSelric *conf_state = conf_req_flag;
615ca1c9b0cSelric
616ca1c9b0cSelric *minor_status = 0;
617ca1c9b0cSelric return GSS_S_COMPLETE;
618ca1c9b0cSelric }
619ca1c9b0cSelric
_gssapi_unwrap_arcfour(OM_uint32 * minor_status,const gsskrb5_ctx context_handle,krb5_context context,const gss_buffer_t input_message_buffer,gss_buffer_t output_message_buffer,int * conf_state,gss_qop_t * qop_state,krb5_keyblock * key)620ca1c9b0cSelric OM_uint32 _gssapi_unwrap_arcfour(OM_uint32 *minor_status,
621ca1c9b0cSelric const gsskrb5_ctx context_handle,
622ca1c9b0cSelric krb5_context context,
623ca1c9b0cSelric const gss_buffer_t input_message_buffer,
624ca1c9b0cSelric gss_buffer_t output_message_buffer,
625ca1c9b0cSelric int *conf_state,
626ca1c9b0cSelric gss_qop_t *qop_state,
627ca1c9b0cSelric krb5_keyblock *key)
628ca1c9b0cSelric {
629ca1c9b0cSelric u_char Klocaldata[16];
630ca1c9b0cSelric krb5_keyblock Klocal;
631ca1c9b0cSelric krb5_error_code ret;
632ca1c9b0cSelric uint32_t seq_number;
633ca1c9b0cSelric size_t datalen;
634ca1c9b0cSelric OM_uint32 omret;
635ca1c9b0cSelric u_char k6_data[16], SND_SEQ[8], Confounder[8];
636ca1c9b0cSelric u_char cksum_data[8];
637ca1c9b0cSelric u_char *p, *p0;
638ca1c9b0cSelric int cmp;
639ca1c9b0cSelric int conf_flag;
640ca1c9b0cSelric size_t padlen = 0, len;
641ca1c9b0cSelric
642ca1c9b0cSelric if (conf_state)
643ca1c9b0cSelric *conf_state = 0;
644ca1c9b0cSelric if (qop_state)
645ca1c9b0cSelric *qop_state = 0;
646ca1c9b0cSelric
647ca1c9b0cSelric p0 = input_message_buffer->value;
648ca1c9b0cSelric
649ca1c9b0cSelric if (IS_DCE_STYLE(context_handle)) {
650ca1c9b0cSelric len = GSS_ARCFOUR_WRAP_TOKEN_SIZE +
651ca1c9b0cSelric GSS_ARCFOUR_WRAP_TOKEN_DCE_DER_HEADER_SIZE;
652ca1c9b0cSelric if (input_message_buffer->length < len)
653ca1c9b0cSelric return GSS_S_BAD_MECH;
654ca1c9b0cSelric } else {
655ca1c9b0cSelric len = input_message_buffer->length;
656ca1c9b0cSelric }
657ca1c9b0cSelric
658ca1c9b0cSelric omret = _gssapi_verify_mech_header(&p0,
659ca1c9b0cSelric len,
660ca1c9b0cSelric GSS_KRB5_MECHANISM);
661ca1c9b0cSelric if (omret)
662ca1c9b0cSelric return omret;
663ca1c9b0cSelric
664ca1c9b0cSelric /* length of mech header */
665ca1c9b0cSelric len = (p0 - (u_char *)input_message_buffer->value) +
666ca1c9b0cSelric GSS_ARCFOUR_WRAP_TOKEN_SIZE;
667ca1c9b0cSelric
668ca1c9b0cSelric if (len > input_message_buffer->length)
669ca1c9b0cSelric return GSS_S_BAD_MECH;
670ca1c9b0cSelric
671ca1c9b0cSelric /* length of data */
672ca1c9b0cSelric datalen = input_message_buffer->length - len;
673ca1c9b0cSelric
674ca1c9b0cSelric p = p0;
675ca1c9b0cSelric
676ca1c9b0cSelric if (memcmp(p, "\x02\x01", 2) != 0)
677ca1c9b0cSelric return GSS_S_BAD_SIG;
678ca1c9b0cSelric p += 2;
679ca1c9b0cSelric if (memcmp(p, "\x11\x00", 2) != 0) /* SGN_ALG = HMAC MD5 ARCFOUR */
680ca1c9b0cSelric return GSS_S_BAD_SIG;
681ca1c9b0cSelric p += 2;
682ca1c9b0cSelric
683ca1c9b0cSelric if (memcmp (p, "\x10\x00", 2) == 0)
684ca1c9b0cSelric conf_flag = 1;
685ca1c9b0cSelric else if (memcmp (p, "\xff\xff", 2) == 0)
686ca1c9b0cSelric conf_flag = 0;
687ca1c9b0cSelric else
688ca1c9b0cSelric return GSS_S_BAD_SIG;
689ca1c9b0cSelric
690ca1c9b0cSelric p += 2;
691ca1c9b0cSelric if (memcmp (p, "\xff\xff", 2) != 0)
692ca1c9b0cSelric return GSS_S_BAD_MIC;
693ca1c9b0cSelric p = NULL;
694ca1c9b0cSelric
695ca1c9b0cSelric ret = arcfour_mic_key(context, key,
696ca1c9b0cSelric p0 + 16, 8, /* SGN_CKSUM */
697ca1c9b0cSelric k6_data, sizeof(k6_data));
698ca1c9b0cSelric if (ret) {
699ca1c9b0cSelric *minor_status = ret;
700ca1c9b0cSelric return GSS_S_FAILURE;
701ca1c9b0cSelric }
702ca1c9b0cSelric
703ca1c9b0cSelric {
7046680b65dSchristos EVP_CIPHER_CTX *rc4_key;
7056680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
7066680b65dSchristos EVP_CIPHER_CTX rc4_keys;
7076680b65dSchristos rc4_key = &rc4_keys;
7086680b65dSchristos EVP_CIPHER_CTX_init(rc4_key);
7096680b65dSchristos #else
7106680b65dSchristos rc4_key = EVP_CIPHER_CTX_new();
7116680b65dSchristos #endif
712ca1c9b0cSelric
7137b2118deSchristos if (!EVP_CipherInit_ex(rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1)) {
7147b2118deSchristos *minor_status = EINVAL;
7157b2118deSchristos return GSS_S_FAILURE;
7167b2118deSchristos }
7176680b65dSchristos EVP_Cipher(rc4_key, SND_SEQ, p0 + 8, 8);
7186680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
7196680b65dSchristos EVP_CIPHER_CTX_cleanup(rc4_key);
7206680b65dSchristos #else
7216680b65dSchristos EVP_CIPHER_CTX_free(rc4_key);
7226680b65dSchristos #endif
723241bea01Schristos memset_s(k6_data, sizeof(k6_data), 0, sizeof(k6_data));
724ca1c9b0cSelric }
725ca1c9b0cSelric
726ca1c9b0cSelric _gsskrb5_decode_be_om_uint32(SND_SEQ, &seq_number);
727ca1c9b0cSelric
728ca1c9b0cSelric if (context_handle->more_flags & LOCAL)
729*afab4e30Schristos cmp = (ct_memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4) != 0);
730ca1c9b0cSelric else
731*afab4e30Schristos cmp = (ct_memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4) != 0);
732ca1c9b0cSelric
733ca1c9b0cSelric if (cmp != 0) {
734ca1c9b0cSelric *minor_status = 0;
735ca1c9b0cSelric return GSS_S_BAD_MIC;
736ca1c9b0cSelric }
737ca1c9b0cSelric
738ca1c9b0cSelric {
739ca1c9b0cSelric int i;
740ca1c9b0cSelric
741ca1c9b0cSelric Klocal.keytype = key->keytype;
742ca1c9b0cSelric Klocal.keyvalue.data = Klocaldata;
743ca1c9b0cSelric Klocal.keyvalue.length = sizeof(Klocaldata);
744ca1c9b0cSelric
745ca1c9b0cSelric for (i = 0; i < 16; i++)
746ca1c9b0cSelric Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0;
747ca1c9b0cSelric }
748ca1c9b0cSelric ret = arcfour_mic_key(context, &Klocal,
749ca1c9b0cSelric SND_SEQ, 4,
750ca1c9b0cSelric k6_data, sizeof(k6_data));
751241bea01Schristos memset_s(Klocaldata, sizeof(Klocaldata), 0, sizeof(Klocaldata));
752ca1c9b0cSelric if (ret) {
753ca1c9b0cSelric *minor_status = ret;
754ca1c9b0cSelric return GSS_S_FAILURE;
755ca1c9b0cSelric }
756ca1c9b0cSelric
757ca1c9b0cSelric output_message_buffer->value = malloc(datalen);
758ca1c9b0cSelric if (output_message_buffer->value == NULL) {
759ca1c9b0cSelric *minor_status = ENOMEM;
760ca1c9b0cSelric return GSS_S_FAILURE;
761ca1c9b0cSelric }
762ca1c9b0cSelric output_message_buffer->length = datalen;
763ca1c9b0cSelric
764ca1c9b0cSelric if(conf_flag) {
7656680b65dSchristos EVP_CIPHER_CTX *rc4_key;
7666680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
7676680b65dSchristos EVP_CIPHER_CTX rc4_keys;
7686680b65dSchristos rc4_key = &rc4_keys;
7696680b65dSchristos EVP_CIPHER_CTX_init(rc4_key);
7706680b65dSchristos #else
7716680b65dSchristos rc4_key = EVP_CIPHER_CTX_new();
7726680b65dSchristos #endif
7737b2118deSchristos if (!EVP_CipherInit_ex(rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1)) {
7747b2118deSchristos *minor_status = EINVAL;
7757b2118deSchristos return GSS_S_FAILURE;
7767b2118deSchristos }
7776680b65dSchristos EVP_Cipher(rc4_key, Confounder, p0 + 24, 8);
7786680b65dSchristos EVP_Cipher(rc4_key, output_message_buffer->value, p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE, datalen);
7796680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
7806680b65dSchristos EVP_CIPHER_CTX_cleanup(rc4_key);
7816680b65dSchristos #else
7826680b65dSchristos EVP_CIPHER_CTX_free(rc4_key);
7836680b65dSchristos #endif
784ca1c9b0cSelric } else {
785ca1c9b0cSelric memcpy(Confounder, p0 + 24, 8); /* Confounder */
786ca1c9b0cSelric memcpy(output_message_buffer->value,
787ca1c9b0cSelric p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE,
788ca1c9b0cSelric datalen);
789ca1c9b0cSelric }
790241bea01Schristos memset_s(k6_data, sizeof(k6_data), 0, sizeof(k6_data));
791ca1c9b0cSelric
792ca1c9b0cSelric if (!IS_DCE_STYLE(context_handle)) {
793ca1c9b0cSelric ret = _gssapi_verify_pad(output_message_buffer, datalen, &padlen);
794ca1c9b0cSelric if (ret) {
795ca1c9b0cSelric _gsskrb5_release_buffer(minor_status, output_message_buffer);
796ca1c9b0cSelric *minor_status = 0;
797ca1c9b0cSelric return ret;
798ca1c9b0cSelric }
799ca1c9b0cSelric output_message_buffer->length -= padlen;
800ca1c9b0cSelric }
801ca1c9b0cSelric
802ca1c9b0cSelric ret = arcfour_mic_cksum(context,
803ca1c9b0cSelric key, KRB5_KU_USAGE_SEAL,
804ca1c9b0cSelric cksum_data, sizeof(cksum_data),
805ca1c9b0cSelric p0, 8,
806ca1c9b0cSelric Confounder, sizeof(Confounder),
807ca1c9b0cSelric output_message_buffer->value,
808ca1c9b0cSelric output_message_buffer->length + padlen);
809ca1c9b0cSelric if (ret) {
810ca1c9b0cSelric _gsskrb5_release_buffer(minor_status, output_message_buffer);
811ca1c9b0cSelric *minor_status = ret;
812ca1c9b0cSelric return GSS_S_FAILURE;
813ca1c9b0cSelric }
814ca1c9b0cSelric
815*afab4e30Schristos cmp = (ct_memcmp(cksum_data, p0 + 16, 8) == 0); /* SGN_CKSUM */
816ca1c9b0cSelric if (cmp) {
817ca1c9b0cSelric _gsskrb5_release_buffer(minor_status, output_message_buffer);
818ca1c9b0cSelric *minor_status = 0;
819ca1c9b0cSelric return GSS_S_BAD_MIC;
820ca1c9b0cSelric }
821ca1c9b0cSelric
822ca1c9b0cSelric HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
823ca1c9b0cSelric omret = _gssapi_msg_order_check(context_handle->order, seq_number);
824ca1c9b0cSelric HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
825ca1c9b0cSelric if (omret)
826ca1c9b0cSelric return omret;
827ca1c9b0cSelric
828ca1c9b0cSelric if (conf_state)
829ca1c9b0cSelric *conf_state = conf_flag;
830ca1c9b0cSelric
831ca1c9b0cSelric *minor_status = 0;
832ca1c9b0cSelric return GSS_S_COMPLETE;
833ca1c9b0cSelric }
834ca1c9b0cSelric
835ca1c9b0cSelric static OM_uint32
max_wrap_length_arcfour(const gsskrb5_ctx ctx,krb5_crypto crypto,size_t input_length,OM_uint32 * max_input_size)836ca1c9b0cSelric max_wrap_length_arcfour(const gsskrb5_ctx ctx,
837ca1c9b0cSelric krb5_crypto crypto,
838ca1c9b0cSelric size_t input_length,
839ca1c9b0cSelric OM_uint32 *max_input_size)
840ca1c9b0cSelric {
841ca1c9b0cSelric /*
842ca1c9b0cSelric * if GSS_C_DCE_STYLE is in use:
843ca1c9b0cSelric * - we only need to encapsulate the WRAP token
844ca1c9b0cSelric * However, since this is a fixed since, we just
845ca1c9b0cSelric */
846ca1c9b0cSelric if (IS_DCE_STYLE(ctx)) {
847ca1c9b0cSelric size_t len, total_len;
848ca1c9b0cSelric
849ca1c9b0cSelric len = GSS_ARCFOUR_WRAP_TOKEN_SIZE;
850ca1c9b0cSelric _gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
851ca1c9b0cSelric
852ca1c9b0cSelric if (input_length < len)
853ca1c9b0cSelric *max_input_size = 0;
854ca1c9b0cSelric else
855ca1c9b0cSelric *max_input_size = input_length - len;
856ca1c9b0cSelric
857ca1c9b0cSelric } else {
858ca1c9b0cSelric size_t extrasize = GSS_ARCFOUR_WRAP_TOKEN_SIZE;
859ca1c9b0cSelric size_t blocksize = 8;
860ca1c9b0cSelric size_t len, total_len;
861ca1c9b0cSelric
862ca1c9b0cSelric len = 8 + input_length + blocksize + extrasize;
863ca1c9b0cSelric
864ca1c9b0cSelric _gsskrb5_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
865ca1c9b0cSelric
866ca1c9b0cSelric total_len -= input_length; /* token length */
867ca1c9b0cSelric if (total_len < input_length) {
868ca1c9b0cSelric *max_input_size = (input_length - total_len);
869ca1c9b0cSelric (*max_input_size) &= (~(OM_uint32)(blocksize - 1));
870ca1c9b0cSelric } else {
871ca1c9b0cSelric *max_input_size = 0;
872ca1c9b0cSelric }
873ca1c9b0cSelric }
874ca1c9b0cSelric
875ca1c9b0cSelric return GSS_S_COMPLETE;
876ca1c9b0cSelric }
877ca1c9b0cSelric
878ca1c9b0cSelric OM_uint32
_gssapi_wrap_size_arcfour(OM_uint32 * minor_status,const gsskrb5_ctx ctx,krb5_context context,int conf_req_flag,gss_qop_t qop_req,OM_uint32 req_output_size,OM_uint32 * max_input_size,krb5_keyblock * key)879ca1c9b0cSelric _gssapi_wrap_size_arcfour(OM_uint32 *minor_status,
880ca1c9b0cSelric const gsskrb5_ctx ctx,
881ca1c9b0cSelric krb5_context context,
882ca1c9b0cSelric int conf_req_flag,
883ca1c9b0cSelric gss_qop_t qop_req,
884ca1c9b0cSelric OM_uint32 req_output_size,
885ca1c9b0cSelric OM_uint32 *max_input_size,
886ca1c9b0cSelric krb5_keyblock *key)
887ca1c9b0cSelric {
888ca1c9b0cSelric krb5_error_code ret;
889ca1c9b0cSelric krb5_crypto crypto;
890ca1c9b0cSelric
891ca1c9b0cSelric ret = krb5_crypto_init(context, key, 0, &crypto);
892ca1c9b0cSelric if (ret != 0) {
893ca1c9b0cSelric *minor_status = ret;
894ca1c9b0cSelric return GSS_S_FAILURE;
895ca1c9b0cSelric }
896ca1c9b0cSelric
897ca1c9b0cSelric ret = max_wrap_length_arcfour(ctx, crypto,
898ca1c9b0cSelric req_output_size, max_input_size);
899ca1c9b0cSelric if (ret != 0) {
900ca1c9b0cSelric *minor_status = ret;
901ca1c9b0cSelric krb5_crypto_destroy(context, crypto);
902ca1c9b0cSelric return GSS_S_FAILURE;
903ca1c9b0cSelric }
904ca1c9b0cSelric
905ca1c9b0cSelric krb5_crypto_destroy(context, crypto);
906ca1c9b0cSelric
907ca1c9b0cSelric return GSS_S_COMPLETE;
908ca1c9b0cSelric }
909b9d004c6Schristos
910b9d004c6Schristos OM_uint32
_gssapi_wrap_iov_length_arcfour(OM_uint32 * minor_status,gsskrb5_ctx ctx,krb5_context context,int conf_req_flag,gss_qop_t qop_req,int * conf_state,gss_iov_buffer_desc * iov,int iov_count)911b9d004c6Schristos _gssapi_wrap_iov_length_arcfour(OM_uint32 *minor_status,
912b9d004c6Schristos gsskrb5_ctx ctx,
913b9d004c6Schristos krb5_context context,
914b9d004c6Schristos int conf_req_flag,
915b9d004c6Schristos gss_qop_t qop_req,
916b9d004c6Schristos int *conf_state,
917b9d004c6Schristos gss_iov_buffer_desc *iov,
918b9d004c6Schristos int iov_count)
919b9d004c6Schristos {
920b9d004c6Schristos OM_uint32 major_status;
921b9d004c6Schristos size_t data_len = 0;
922b9d004c6Schristos int i;
923b9d004c6Schristos gss_iov_buffer_desc *header = NULL;
924b9d004c6Schristos gss_iov_buffer_desc *padding = NULL;
925b9d004c6Schristos gss_iov_buffer_desc *trailer = NULL;
926b9d004c6Schristos
927b9d004c6Schristos *minor_status = 0;
928b9d004c6Schristos
929b9d004c6Schristos for (i = 0; i < iov_count; i++) {
930b9d004c6Schristos switch(GSS_IOV_BUFFER_TYPE(iov[i].type)) {
931b9d004c6Schristos case GSS_IOV_BUFFER_TYPE_EMPTY:
932b9d004c6Schristos break;
933b9d004c6Schristos case GSS_IOV_BUFFER_TYPE_DATA:
934b9d004c6Schristos data_len += iov[i].buffer.length;
935b9d004c6Schristos break;
936b9d004c6Schristos case GSS_IOV_BUFFER_TYPE_HEADER:
937b9d004c6Schristos if (header != NULL) {
938b9d004c6Schristos *minor_status = EINVAL;
939b9d004c6Schristos return GSS_S_FAILURE;
940b9d004c6Schristos }
941b9d004c6Schristos header = &iov[i];
942b9d004c6Schristos break;
943b9d004c6Schristos case GSS_IOV_BUFFER_TYPE_TRAILER:
944b9d004c6Schristos if (trailer != NULL) {
945b9d004c6Schristos *minor_status = EINVAL;
946b9d004c6Schristos return GSS_S_FAILURE;
947b9d004c6Schristos }
948b9d004c6Schristos trailer = &iov[i];
949b9d004c6Schristos break;
950b9d004c6Schristos case GSS_IOV_BUFFER_TYPE_PADDING:
951b9d004c6Schristos if (padding != NULL) {
952b9d004c6Schristos *minor_status = EINVAL;
953b9d004c6Schristos return GSS_S_FAILURE;
954b9d004c6Schristos }
955b9d004c6Schristos padding = &iov[i];
956b9d004c6Schristos break;
957b9d004c6Schristos case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
958b9d004c6Schristos break;
959b9d004c6Schristos default:
960b9d004c6Schristos *minor_status = EINVAL;
961b9d004c6Schristos return GSS_S_FAILURE;
962b9d004c6Schristos }
963b9d004c6Schristos }
964b9d004c6Schristos
965*afab4e30Schristos if (header == NULL) {
966*afab4e30Schristos *minor_status = EINVAL;
967*afab4e30Schristos return GSS_S_FAILURE;
968*afab4e30Schristos }
969*afab4e30Schristos
970*afab4e30Schristos major_status = _gk_verify_buffers(minor_status, ctx, header,
971*afab4e30Schristos padding, trailer, FALSE);
972b9d004c6Schristos if (major_status != GSS_S_COMPLETE) {
973b9d004c6Schristos return major_status;
974b9d004c6Schristos }
975b9d004c6Schristos
976b9d004c6Schristos if (IS_DCE_STYLE(ctx)) {
977b9d004c6Schristos size_t len = GSS_ARCFOUR_WRAP_TOKEN_SIZE;
978b9d004c6Schristos size_t total_len;
979b9d004c6Schristos _gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
980b9d004c6Schristos header->buffer.length = total_len;
981b9d004c6Schristos } else {
982b9d004c6Schristos size_t len;
983b9d004c6Schristos size_t total_len;
984b9d004c6Schristos if (padding) {
985b9d004c6Schristos data_len += 1; /* padding */
986b9d004c6Schristos }
987b9d004c6Schristos len = data_len + GSS_ARCFOUR_WRAP_TOKEN_SIZE;
988b9d004c6Schristos _gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
989b9d004c6Schristos header->buffer.length = total_len - data_len;
990b9d004c6Schristos }
991b9d004c6Schristos
992b9d004c6Schristos if (trailer) {
993b9d004c6Schristos trailer->buffer.length = 0;
994b9d004c6Schristos }
995b9d004c6Schristos
996b9d004c6Schristos if (padding) {
997b9d004c6Schristos padding->buffer.length = 1;
998b9d004c6Schristos }
999b9d004c6Schristos
1000b9d004c6Schristos return GSS_S_COMPLETE;
1001b9d004c6Schristos }
1002b9d004c6Schristos
1003b9d004c6Schristos OM_uint32
_gssapi_wrap_iov_arcfour(OM_uint32 * minor_status,gsskrb5_ctx ctx,krb5_context context,int conf_req_flag,int * conf_state,gss_iov_buffer_desc * iov,int iov_count,krb5_keyblock * key)1004b9d004c6Schristos _gssapi_wrap_iov_arcfour(OM_uint32 *minor_status,
1005b9d004c6Schristos gsskrb5_ctx ctx,
1006b9d004c6Schristos krb5_context context,
1007b9d004c6Schristos int conf_req_flag,
1008b9d004c6Schristos int *conf_state,
1009b9d004c6Schristos gss_iov_buffer_desc *iov,
1010b9d004c6Schristos int iov_count,
1011b9d004c6Schristos krb5_keyblock *key)
1012b9d004c6Schristos {
1013b9d004c6Schristos OM_uint32 major_status, junk;
1014b9d004c6Schristos gss_iov_buffer_desc *header, *padding, *trailer;
1015b9d004c6Schristos krb5_error_code kret;
1016b9d004c6Schristos int32_t seq_number;
1017b9d004c6Schristos u_char Klocaldata[16], k6_data[16], *p, *p0;
1018b9d004c6Schristos size_t make_len = 0;
1019b9d004c6Schristos size_t header_len = 0;
1020b9d004c6Schristos size_t data_len = 0;
1021b9d004c6Schristos krb5_keyblock Klocal;
1022b9d004c6Schristos int i;
1023b9d004c6Schristos
1024b9d004c6Schristos header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
1025b9d004c6Schristos padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
1026b9d004c6Schristos trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
1027b9d004c6Schristos
1028*afab4e30Schristos major_status = _gk_verify_buffers(minor_status, ctx, header,
1029*afab4e30Schristos padding, trailer, FALSE);
1030b9d004c6Schristos if (major_status != GSS_S_COMPLETE) {
1031b9d004c6Schristos return major_status;
1032b9d004c6Schristos }
1033b9d004c6Schristos
1034b9d004c6Schristos for (i = 0; i < iov_count; i++) {
1035b9d004c6Schristos switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
1036b9d004c6Schristos case GSS_IOV_BUFFER_TYPE_DATA:
1037b9d004c6Schristos break;
1038b9d004c6Schristos default:
1039b9d004c6Schristos continue;
1040b9d004c6Schristos }
1041b9d004c6Schristos
1042b9d004c6Schristos data_len += iov[i].buffer.length;
1043b9d004c6Schristos }
1044b9d004c6Schristos
1045b9d004c6Schristos if (padding) {
1046b9d004c6Schristos data_len += 1;
1047b9d004c6Schristos }
1048b9d004c6Schristos
1049b9d004c6Schristos if (IS_DCE_STYLE(ctx)) {
1050b9d004c6Schristos size_t unwrapped_len;
1051b9d004c6Schristos unwrapped_len = GSS_ARCFOUR_WRAP_TOKEN_SIZE;
1052b9d004c6Schristos _gssapi_encap_length(unwrapped_len,
1053b9d004c6Schristos &make_len,
1054b9d004c6Schristos &header_len,
1055b9d004c6Schristos GSS_KRB5_MECHANISM);
1056b9d004c6Schristos } else {
1057b9d004c6Schristos size_t unwrapped_len;
1058b9d004c6Schristos unwrapped_len = GSS_ARCFOUR_WRAP_TOKEN_SIZE + data_len;
1059b9d004c6Schristos _gssapi_encap_length(unwrapped_len,
1060b9d004c6Schristos &make_len,
1061b9d004c6Schristos &header_len,
1062b9d004c6Schristos GSS_KRB5_MECHANISM);
1063b9d004c6Schristos header_len -= data_len;
1064b9d004c6Schristos }
1065b9d004c6Schristos
1066*afab4e30Schristos if (GSS_IOV_BUFFER_FLAGS(header->type) & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
1067b9d004c6Schristos major_status = _gk_allocate_buffer(minor_status, header,
1068b9d004c6Schristos header_len);
1069b9d004c6Schristos if (major_status != GSS_S_COMPLETE)
1070b9d004c6Schristos goto failure;
1071b9d004c6Schristos } else if (header->buffer.length < header_len) {
1072b9d004c6Schristos *minor_status = KRB5_BAD_MSIZE;
1073b9d004c6Schristos major_status = GSS_S_FAILURE;
1074b9d004c6Schristos goto failure;
1075b9d004c6Schristos } else {
1076b9d004c6Schristos header->buffer.length = header_len;
1077b9d004c6Schristos }
1078b9d004c6Schristos
1079b9d004c6Schristos if (padding) {
1080*afab4e30Schristos if (GSS_IOV_BUFFER_FLAGS(padding->type) & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
1081b9d004c6Schristos major_status = _gk_allocate_buffer(minor_status, padding, 1);
1082b9d004c6Schristos if (major_status != GSS_S_COMPLETE)
1083b9d004c6Schristos goto failure;
1084b9d004c6Schristos } else if (padding->buffer.length < 1) {
1085b9d004c6Schristos *minor_status = KRB5_BAD_MSIZE;
1086b9d004c6Schristos major_status = GSS_S_FAILURE;
1087b9d004c6Schristos goto failure;
1088b9d004c6Schristos } else {
1089b9d004c6Schristos padding->buffer.length = 1;
1090b9d004c6Schristos }
1091b9d004c6Schristos memset(padding->buffer.value, 1, 1);
1092b9d004c6Schristos }
1093b9d004c6Schristos
1094b9d004c6Schristos if (trailer) {
1095b9d004c6Schristos trailer->buffer.length = 0;
1096b9d004c6Schristos trailer->buffer.value = NULL;
1097b9d004c6Schristos }
1098b9d004c6Schristos
1099b9d004c6Schristos p0 = _gssapi_make_mech_header(header->buffer.value,
1100b9d004c6Schristos make_len,
1101b9d004c6Schristos GSS_KRB5_MECHANISM);
1102b9d004c6Schristos p = p0;
1103b9d004c6Schristos
1104b9d004c6Schristos *p++ = 0x02; /* TOK_ID */
1105b9d004c6Schristos *p++ = 0x01;
1106b9d004c6Schristos *p++ = 0x11; /* SGN_ALG */
1107b9d004c6Schristos *p++ = 0x00;
1108b9d004c6Schristos if (conf_req_flag) {
1109b9d004c6Schristos *p++ = 0x10; /* SEAL_ALG */
1110b9d004c6Schristos *p++ = 0x00;
1111b9d004c6Schristos } else {
1112b9d004c6Schristos *p++ = 0xff; /* SEAL_ALG */
1113b9d004c6Schristos *p++ = 0xff;
1114b9d004c6Schristos }
1115b9d004c6Schristos *p++ = 0xff; /* Filler */
1116b9d004c6Schristos *p++ = 0xff;
1117b9d004c6Schristos
1118b9d004c6Schristos p = NULL;
1119b9d004c6Schristos
1120b9d004c6Schristos HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
1121b9d004c6Schristos krb5_auth_con_getlocalseqnumber(context,
1122b9d004c6Schristos ctx->auth_context,
1123b9d004c6Schristos &seq_number);
1124b9d004c6Schristos _gsskrb5_encode_be_om_uint32(seq_number, p0 + 8);
1125b9d004c6Schristos
1126b9d004c6Schristos krb5_auth_con_setlocalseqnumber(context,
1127b9d004c6Schristos ctx->auth_context,
1128b9d004c6Schristos ++seq_number);
1129b9d004c6Schristos HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
1130b9d004c6Schristos
1131b9d004c6Schristos memset(p0 + 8 + 4,
1132b9d004c6Schristos (ctx->more_flags & LOCAL) ? 0 : 0xff,
1133b9d004c6Schristos 4);
1134b9d004c6Schristos
1135b9d004c6Schristos krb5_generate_random_block(p0 + 24, 8); /* fill in Confounder */
1136b9d004c6Schristos
1137b9d004c6Schristos /* Sign Data */
1138b9d004c6Schristos kret = arcfour_mic_cksum_iov(context,
1139b9d004c6Schristos key, KRB5_KU_USAGE_SEAL,
1140b9d004c6Schristos p0 + 16, 8, /* SGN_CKSUM */
1141b9d004c6Schristos p0, 8, /* TOK_ID, SGN_ALG, SEAL_ALG, Filler */
1142b9d004c6Schristos p0 + 24, 8, /* Confounder */
1143b9d004c6Schristos iov, iov_count, /* Data + SignOnly */
1144b9d004c6Schristos padding); /* padding */
1145b9d004c6Schristos if (kret) {
1146b9d004c6Schristos *minor_status = kret;
1147b9d004c6Schristos major_status = GSS_S_FAILURE;
1148b9d004c6Schristos goto failure;
1149b9d004c6Schristos }
1150b9d004c6Schristos
1151b9d004c6Schristos Klocal.keytype = key->keytype;
1152b9d004c6Schristos Klocal.keyvalue.data = Klocaldata;
1153b9d004c6Schristos Klocal.keyvalue.length = sizeof(Klocaldata);
1154b9d004c6Schristos
1155b9d004c6Schristos for (i = 0; i < 16; i++) {
1156b9d004c6Schristos Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0;
1157b9d004c6Schristos }
1158b9d004c6Schristos kret = arcfour_mic_key(context, &Klocal,
1159b9d004c6Schristos p0 + 8, 4, /* SND_SEQ */
1160b9d004c6Schristos k6_data, sizeof(k6_data));
1161241bea01Schristos memset_s(Klocaldata, sizeof(Klocaldata), 0, sizeof(Klocaldata));
1162b9d004c6Schristos if (kret) {
1163b9d004c6Schristos *minor_status = kret;
1164b9d004c6Schristos major_status = GSS_S_FAILURE;
1165b9d004c6Schristos goto failure;
1166b9d004c6Schristos }
1167b9d004c6Schristos
1168b9d004c6Schristos if (conf_req_flag) {
11696680b65dSchristos EVP_CIPHER_CTX *rc4_key;
11706680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
11716680b65dSchristos EVP_CIPHER_CTX rc4_keys;
11726680b65dSchristos rc4_key = &rc4_keys;
11736680b65dSchristos EVP_CIPHER_CTX_init(rc4_key);
11746680b65dSchristos #else
11756680b65dSchristos rc4_key = EVP_CIPHER_CTX_new();
11766680b65dSchristos #endif
11777b2118deSchristos if (!EVP_CipherInit_ex(rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1)) {
11787b2118deSchristos *minor_status = EINVAL;
11797b2118deSchristos return GSS_S_FAILURE;
11807b2118deSchristos }
1181b9d004c6Schristos
1182b9d004c6Schristos /* Confounder */
11836680b65dSchristos EVP_Cipher(rc4_key, p0 + 24, p0 + 24, 8);
1184b9d004c6Schristos
1185b9d004c6Schristos /* Seal Data */
1186b9d004c6Schristos for (i=0; i < iov_count; i++) {
1187b9d004c6Schristos switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
1188b9d004c6Schristos case GSS_IOV_BUFFER_TYPE_DATA:
1189b9d004c6Schristos break;
1190b9d004c6Schristos default:
1191b9d004c6Schristos continue;
1192b9d004c6Schristos }
1193b9d004c6Schristos
11946680b65dSchristos EVP_Cipher(rc4_key, iov[i].buffer.value,
1195b9d004c6Schristos iov[i].buffer.value, iov[i].buffer.length);
1196b9d004c6Schristos }
1197b9d004c6Schristos
1198b9d004c6Schristos /* Padding */
1199b9d004c6Schristos if (padding) {
12006680b65dSchristos EVP_Cipher(rc4_key, padding->buffer.value,
1201b9d004c6Schristos padding->buffer.value, padding->buffer.length);
1202b9d004c6Schristos }
1203b9d004c6Schristos
12046680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
12056680b65dSchristos EVP_CIPHER_CTX_cleanup(rc4_key);
12066680b65dSchristos #else
12076680b65dSchristos EVP_CIPHER_CTX_free(rc4_key);
12086680b65dSchristos #endif
1209b9d004c6Schristos }
1210241bea01Schristos memset_s(k6_data, sizeof(k6_data), 0, sizeof(k6_data));
1211b9d004c6Schristos
1212b9d004c6Schristos kret = arcfour_mic_key(context, key,
1213b9d004c6Schristos p0 + 16, 8, /* SGN_CKSUM */
1214b9d004c6Schristos k6_data, sizeof(k6_data));
1215b9d004c6Schristos if (kret) {
1216b9d004c6Schristos *minor_status = kret;
1217b9d004c6Schristos major_status = GSS_S_FAILURE;
1218b9d004c6Schristos return major_status;
1219b9d004c6Schristos }
1220b9d004c6Schristos
1221b9d004c6Schristos {
12226680b65dSchristos EVP_CIPHER_CTX *rc4_key;
12236680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
12246680b65dSchristos EVP_CIPHER_CTX rc4_keys;
12256680b65dSchristos rc4_key = &rc4_keys;
12266680b65dSchristos EVP_CIPHER_CTX_init(rc4_key);
12276680b65dSchristos #else
12286680b65dSchristos rc4_key = EVP_CIPHER_CTX_new();
12296680b65dSchristos #endif
12307b2118deSchristos if (!EVP_CipherInit_ex(rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1)) {
12317b2118deSchristos *minor_status = EINVAL;
12327b2118deSchristos return GSS_S_FAILURE;
12337b2118deSchristos }
12346680b65dSchristos EVP_Cipher(rc4_key, p0 + 8, p0 + 8, 8); /* SND_SEQ */
12356680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
12366680b65dSchristos EVP_CIPHER_CTX_cleanup(rc4_key);
12376680b65dSchristos #else
12386680b65dSchristos EVP_CIPHER_CTX_free(rc4_key);
12396680b65dSchristos #endif
1240b9d004c6Schristos
1241241bea01Schristos memset_s(k6_data, sizeof(k6_data), 0, sizeof(k6_data));
1242b9d004c6Schristos }
1243b9d004c6Schristos
1244b9d004c6Schristos if (conf_state)
1245b9d004c6Schristos *conf_state = conf_req_flag;
1246b9d004c6Schristos
1247b9d004c6Schristos *minor_status = 0;
1248b9d004c6Schristos return GSS_S_COMPLETE;
1249b9d004c6Schristos
1250b9d004c6Schristos failure:
1251b9d004c6Schristos
1252b9d004c6Schristos gss_release_iov_buffer(&junk, iov, iov_count);
1253b9d004c6Schristos
1254b9d004c6Schristos return major_status;
1255b9d004c6Schristos }
1256b9d004c6Schristos
1257b9d004c6Schristos OM_uint32
_gssapi_unwrap_iov_arcfour(OM_uint32 * minor_status,gsskrb5_ctx ctx,krb5_context context,int * pconf_state,gss_qop_t * pqop_state,gss_iov_buffer_desc * iov,int iov_count,krb5_keyblock * key)1258b9d004c6Schristos _gssapi_unwrap_iov_arcfour(OM_uint32 *minor_status,
1259b9d004c6Schristos gsskrb5_ctx ctx,
1260b9d004c6Schristos krb5_context context,
1261b9d004c6Schristos int *pconf_state,
1262b9d004c6Schristos gss_qop_t *pqop_state,
1263b9d004c6Schristos gss_iov_buffer_desc *iov,
1264b9d004c6Schristos int iov_count,
1265b9d004c6Schristos krb5_keyblock *key)
1266b9d004c6Schristos {
1267b9d004c6Schristos OM_uint32 major_status;
1268b9d004c6Schristos gss_iov_buffer_desc *header, *padding, *trailer;
1269b9d004c6Schristos krb5_keyblock Klocal;
1270b9d004c6Schristos uint8_t Klocaldata[16];
1271b9d004c6Schristos uint8_t k6_data[16], snd_seq[8], Confounder[8];
1272b9d004c6Schristos uint8_t cksum_data[8];
1273b9d004c6Schristos uint8_t *_p = NULL;
1274b9d004c6Schristos const uint8_t *p, *p0;
1275b9d004c6Schristos size_t verify_len = 0;
1276b9d004c6Schristos uint32_t seq_number;
1277b9d004c6Schristos size_t hlen = 0;
1278b9d004c6Schristos int conf_state;
1279b9d004c6Schristos int cmp;
1280b9d004c6Schristos size_t i;
1281b9d004c6Schristos krb5_error_code kret;
1282b9d004c6Schristos OM_uint32 ret;
1283b9d004c6Schristos
1284b9d004c6Schristos if (pconf_state != NULL) {
1285b9d004c6Schristos *pconf_state = 0;
1286b9d004c6Schristos }
1287b9d004c6Schristos if (pqop_state != NULL) {
1288b9d004c6Schristos *pqop_state = 0;
1289b9d004c6Schristos }
1290b9d004c6Schristos
1291b9d004c6Schristos header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
1292b9d004c6Schristos padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
1293b9d004c6Schristos trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
1294b9d004c6Schristos
1295b9d004c6Schristos /* Check if the packet is correct */
1296b9d004c6Schristos major_status = _gk_verify_buffers(minor_status,
1297b9d004c6Schristos ctx,
1298b9d004c6Schristos header,
1299b9d004c6Schristos padding,
1300*afab4e30Schristos trailer,
1301*afab4e30Schristos FALSE); /* behaves as stream cipher */
1302b9d004c6Schristos if (major_status != GSS_S_COMPLETE) {
1303b9d004c6Schristos return major_status;
1304b9d004c6Schristos }
1305b9d004c6Schristos
1306b9d004c6Schristos if (padding != NULL && padding->buffer.length != 1) {
1307b9d004c6Schristos *minor_status = EINVAL;
1308b9d004c6Schristos return GSS_S_FAILURE;
1309b9d004c6Schristos }
1310b9d004c6Schristos
1311b9d004c6Schristos verify_len = header->buffer.length;
1312*afab4e30Schristos
1313*afab4e30Schristos if (!IS_DCE_STYLE(context)) {
1314*afab4e30Schristos for (i = 0; i < iov_count; i++) {
1315*afab4e30Schristos /* length in header also includes data and padding */
1316*afab4e30Schristos if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA)
1317*afab4e30Schristos verify_len += iov[i].buffer.length;
1318b9d004c6Schristos }
1319*afab4e30Schristos
1320*afab4e30Schristos if (padding)
1321*afab4e30Schristos verify_len += padding->buffer.length;
1322*afab4e30Schristos }
1323*afab4e30Schristos
1324b9d004c6Schristos _p = header->buffer.value;
1325b9d004c6Schristos
1326b9d004c6Schristos ret = _gssapi_verify_mech_header(&_p,
1327b9d004c6Schristos verify_len,
1328b9d004c6Schristos GSS_KRB5_MECHANISM);
1329b9d004c6Schristos if (ret) {
1330b9d004c6Schristos return ret;
1331b9d004c6Schristos }
1332b9d004c6Schristos p0 = _p;
1333b9d004c6Schristos
1334b9d004c6Schristos /* length of mech header */
1335b9d004c6Schristos hlen = (p0 - (uint8_t *)header->buffer.value);
1336b9d004c6Schristos hlen += GSS_ARCFOUR_WRAP_TOKEN_SIZE;
1337b9d004c6Schristos
1338b9d004c6Schristos if (hlen > header->buffer.length) {
1339b9d004c6Schristos return GSS_S_BAD_MECH;
1340b9d004c6Schristos }
1341b9d004c6Schristos
1342b9d004c6Schristos p = p0;
1343b9d004c6Schristos
1344b9d004c6Schristos if (memcmp(p, "\x02\x01", 2) != 0)
1345b9d004c6Schristos return GSS_S_BAD_SIG;
1346b9d004c6Schristos p += 2;
1347b9d004c6Schristos if (memcmp(p, "\x11\x00", 2) != 0) /* SGN_ALG = HMAC MD5 ARCFOUR */
1348b9d004c6Schristos return GSS_S_BAD_SIG;
1349b9d004c6Schristos p += 2;
1350b9d004c6Schristos
1351b9d004c6Schristos if (memcmp (p, "\x10\x00", 2) == 0)
1352b9d004c6Schristos conf_state = 1;
1353b9d004c6Schristos else if (memcmp (p, "\xff\xff", 2) == 0)
1354b9d004c6Schristos conf_state = 0;
1355b9d004c6Schristos else
1356b9d004c6Schristos return GSS_S_BAD_SIG;
1357b9d004c6Schristos
1358b9d004c6Schristos p += 2;
1359b9d004c6Schristos if (memcmp (p, "\xff\xff", 2) != 0)
1360b9d004c6Schristos return GSS_S_BAD_MIC;
1361b9d004c6Schristos p = NULL;
1362b9d004c6Schristos
1363b9d004c6Schristos kret = arcfour_mic_key(context,
1364b9d004c6Schristos key,
1365b9d004c6Schristos p0 + 16, /* SGN_CKSUM */
1366b9d004c6Schristos 8, /* SGN_CKSUM_LEN */
1367b9d004c6Schristos k6_data,
1368b9d004c6Schristos sizeof(k6_data));
1369b9d004c6Schristos if (kret) {
1370b9d004c6Schristos *minor_status = kret;
1371b9d004c6Schristos return GSS_S_FAILURE;
1372b9d004c6Schristos }
1373b9d004c6Schristos
1374b9d004c6Schristos {
13756680b65dSchristos EVP_CIPHER_CTX *rc4_key;
13766680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
13776680b65dSchristos EVP_CIPHER_CTX rc4_keys;
13786680b65dSchristos rc4_key = &rc4_keys;
13796680b65dSchristos EVP_CIPHER_CTX_init(rc4_key);
13806680b65dSchristos #else
13816680b65dSchristos rc4_key = EVP_CIPHER_CTX_new();
13826680b65dSchristos #endif
1383b9d004c6Schristos
13846680b65dSchristos EVP_CIPHER_CTX_init(rc4_key);
13857b2118deSchristos if (!EVP_CipherInit_ex(rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1)) {
13867b2118deSchristos *minor_status = EINVAL;
13877b2118deSchristos return GSS_S_FAILURE;
13887b2118deSchristos }
13896680b65dSchristos EVP_Cipher(rc4_key, snd_seq, p0 + 8, 8); /* SND_SEQ */
13906680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
13916680b65dSchristos EVP_CIPHER_CTX_cleanup(rc4_key);
13926680b65dSchristos #else
13936680b65dSchristos EVP_CIPHER_CTX_free(rc4_key);
13946680b65dSchristos #endif
1395b9d004c6Schristos
1396241bea01Schristos memset_s(k6_data, sizeof(k6_data), 0, sizeof(k6_data));
1397b9d004c6Schristos }
1398b9d004c6Schristos
1399b9d004c6Schristos _gsskrb5_decode_be_om_uint32(snd_seq, &seq_number);
1400b9d004c6Schristos
1401b9d004c6Schristos if (ctx->more_flags & LOCAL) {
1402*afab4e30Schristos cmp = (ct_memcmp(&snd_seq[4], "\xff\xff\xff\xff", 4) != 0);
1403b9d004c6Schristos } else {
1404*afab4e30Schristos cmp = (ct_memcmp(&snd_seq[4], "\x00\x00\x00\x00", 4) != 0);
1405b9d004c6Schristos }
1406b9d004c6Schristos if (cmp != 0) {
1407b9d004c6Schristos *minor_status = 0;
1408b9d004c6Schristos return GSS_S_BAD_MIC;
1409b9d004c6Schristos }
1410b9d004c6Schristos
1411b9d004c6Schristos /* keyblock */
1412b9d004c6Schristos Klocal.keytype = key->keytype;
1413b9d004c6Schristos Klocal.keyvalue.data = Klocaldata;
1414b9d004c6Schristos Klocal.keyvalue.length = sizeof(Klocaldata);
1415b9d004c6Schristos
1416b9d004c6Schristos for (i = 0; i < 16; i++) {
1417b9d004c6Schristos Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0;
1418b9d004c6Schristos }
1419b9d004c6Schristos
1420b9d004c6Schristos kret = arcfour_mic_key(context,
1421b9d004c6Schristos &Klocal,
1422b9d004c6Schristos snd_seq,
1423b9d004c6Schristos 4,
1424b9d004c6Schristos k6_data, sizeof(k6_data));
1425241bea01Schristos memset_s(Klocaldata, sizeof(Klocaldata), 0, sizeof(Klocaldata));
1426b9d004c6Schristos if (kret) {
1427b9d004c6Schristos *minor_status = kret;
1428b9d004c6Schristos return GSS_S_FAILURE;
1429b9d004c6Schristos }
1430b9d004c6Schristos
1431b9d004c6Schristos if (conf_state == 1) {
14326680b65dSchristos EVP_CIPHER_CTX *rc4_key;
14336680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
14346680b65dSchristos EVP_CIPHER_CTX rc4_keys;
14356680b65dSchristos rc4_key = &rc4_keys;
14366680b65dSchristos EVP_CIPHER_CTX_init(rc4_key);
14376680b65dSchristos #else
14386680b65dSchristos rc4_key = EVP_CIPHER_CTX_new();
14396680b65dSchristos #endif
1440b9d004c6Schristos
14417b2118deSchristos if (!EVP_CipherInit_ex(rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1)) {
14427b2118deSchristos *minor_status = EINVAL;
14437b2118deSchristos return GSS_S_FAILURE;
14447b2118deSchristos }
1445b9d004c6Schristos
1446b9d004c6Schristos /* Confounder */
14476680b65dSchristos EVP_Cipher(rc4_key, Confounder, p0 + 24, 8);
1448b9d004c6Schristos
1449b9d004c6Schristos /* Data */
1450b9d004c6Schristos for (i = 0; i < iov_count; i++) {
1451b9d004c6Schristos switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
1452b9d004c6Schristos case GSS_IOV_BUFFER_TYPE_DATA:
1453b9d004c6Schristos break;
1454b9d004c6Schristos default:
1455b9d004c6Schristos continue;
1456b9d004c6Schristos }
1457b9d004c6Schristos
14586680b65dSchristos EVP_Cipher(rc4_key, iov[i].buffer.value,
1459b9d004c6Schristos iov[i].buffer.value, iov[i].buffer.length);
1460b9d004c6Schristos }
1461b9d004c6Schristos
1462b9d004c6Schristos /* Padding */
1463b9d004c6Schristos if (padding) {
14646680b65dSchristos EVP_Cipher(rc4_key, padding->buffer.value,
1465b9d004c6Schristos padding->buffer.value, padding->buffer.length);
1466b9d004c6Schristos }
1467b9d004c6Schristos
14686680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
14696680b65dSchristos EVP_CIPHER_CTX_cleanup(rc4_key);
14706680b65dSchristos #else
14716680b65dSchristos EVP_CIPHER_CTX_free(rc4_key);
14726680b65dSchristos #endif
1473b9d004c6Schristos } else {
1474b9d004c6Schristos /* Confounder */
1475b9d004c6Schristos memcpy(Confounder, p0 + 24, 8);
1476b9d004c6Schristos }
1477241bea01Schristos memset_s(k6_data, sizeof(k6_data), 0, sizeof(k6_data));
1478b9d004c6Schristos
1479b9d004c6Schristos /* Prepare the buffer for signing */
1480b9d004c6Schristos kret = arcfour_mic_cksum_iov(context,
1481b9d004c6Schristos key, KRB5_KU_USAGE_SEAL,
1482b9d004c6Schristos cksum_data, sizeof(cksum_data),
1483b9d004c6Schristos p0, 8,
1484b9d004c6Schristos Confounder, sizeof(Confounder),
1485b9d004c6Schristos iov, iov_count,
1486b9d004c6Schristos padding);
1487b9d004c6Schristos if (kret) {
1488b9d004c6Schristos *minor_status = kret;
1489b9d004c6Schristos return GSS_S_FAILURE;
1490b9d004c6Schristos }
1491b9d004c6Schristos
1492b9d004c6Schristos cmp = memcmp(cksum_data, p0 + 16, 8); /* SGN_CKSUM */
1493b9d004c6Schristos if (cmp != 0) {
1494b9d004c6Schristos *minor_status = 0;
1495b9d004c6Schristos return GSS_S_BAD_MIC;
1496b9d004c6Schristos }
1497b9d004c6Schristos
1498b9d004c6Schristos if (padding) {
1499b9d004c6Schristos size_t plen;
1500b9d004c6Schristos
1501b9d004c6Schristos ret = _gssapi_verify_pad(&padding->buffer, 1, &plen);
1502b9d004c6Schristos if (ret) {
1503b9d004c6Schristos *minor_status = 0;
1504b9d004c6Schristos return ret;
1505b9d004c6Schristos }
1506b9d004c6Schristos }
1507b9d004c6Schristos
1508b9d004c6Schristos HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
1509b9d004c6Schristos ret = _gssapi_msg_order_check(ctx->order, seq_number);
1510b9d004c6Schristos HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
1511b9d004c6Schristos if (ret != 0) {
1512b9d004c6Schristos return ret;
1513b9d004c6Schristos }
1514b9d004c6Schristos
1515b9d004c6Schristos if (pconf_state) {
1516b9d004c6Schristos *pconf_state = conf_state;
1517b9d004c6Schristos }
1518b9d004c6Schristos
1519b9d004c6Schristos *minor_status = 0;
1520b9d004c6Schristos return GSS_S_COMPLETE;
1521b9d004c6Schristos }
1522