1178825Sdfr/*
2233294Sstas * Copyright (c) 2006 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
5178825Sdfr *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
9178825Sdfr *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
12178825Sdfr *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
16178825Sdfr *
17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
18233294Sstas *    may be used to endorse or promote products derived from this software
19233294Sstas *    without specific prior written permission.
20178825Sdfr *
21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31233294Sstas * SUCH DAMAGE.
32178825Sdfr */
33178825Sdfr
34233294Sstas#include "ntlm.h"
35178825Sdfr
36178825Sdfruint32_t
37178825Sdfr_krb5_crc_update (const char *p, size_t len, uint32_t res);
38178825Sdfrvoid
39178825Sdfr_krb5_crc_init_table(void);
40178825Sdfr
41178825Sdfr/*
42178825Sdfr *
43178825Sdfr */
44178825Sdfr
45178825Sdfrstatic void
46178825Sdfrencode_le_uint32(uint32_t n, unsigned char *p)
47178825Sdfr{
48178825Sdfr  p[0] = (n >> 0)  & 0xFF;
49178825Sdfr  p[1] = (n >> 8)  & 0xFF;
50178825Sdfr  p[2] = (n >> 16) & 0xFF;
51178825Sdfr  p[3] = (n >> 24) & 0xFF;
52178825Sdfr}
53178825Sdfr
54178825Sdfr
55178825Sdfrstatic void
56178825Sdfrdecode_le_uint32(const void *ptr, uint32_t *n)
57178825Sdfr{
58178825Sdfr    const unsigned char *p = ptr;
59178825Sdfr    *n = (p[0] << 0) | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
60178825Sdfr}
61178825Sdfr
62178825Sdfr/*
63178825Sdfr *
64178825Sdfr */
65178825Sdfr
66178825Sdfrconst char a2i_signmagic[] =
67178825Sdfr    "session key to server-to-client signing key magic constant";
68178825Sdfrconst char a2i_sealmagic[] =
69178825Sdfr    "session key to server-to-client sealing key magic constant";
70178825Sdfrconst char i2a_signmagic[] =
71178825Sdfr    "session key to client-to-server signing key magic constant";
72178825Sdfrconst char i2a_sealmagic[] =
73178825Sdfr    "session key to client-to-server sealing key magic constant";
74178825Sdfr
75178825Sdfr
76178825Sdfrvoid
77178825Sdfr_gss_ntlm_set_key(struct ntlmv2_key *key, int acceptor, int sealsign,
78178825Sdfr		  unsigned char *data, size_t len)
79178825Sdfr{
80178825Sdfr    unsigned char out[16];
81233294Sstas    EVP_MD_CTX *ctx;
82178825Sdfr    const char *signmagic;
83178825Sdfr    const char *sealmagic;
84178825Sdfr
85178825Sdfr    if (acceptor) {
86178825Sdfr	signmagic = a2i_signmagic;
87178825Sdfr	sealmagic = a2i_sealmagic;
88178825Sdfr    } else {
89178825Sdfr	signmagic = i2a_signmagic;
90178825Sdfr	sealmagic = i2a_sealmagic;
91178825Sdfr    }
92178825Sdfr
93178825Sdfr    key->seq = 0;
94178825Sdfr
95233294Sstas    ctx = EVP_MD_CTX_create();
96233294Sstas    EVP_DigestInit_ex(ctx, EVP_md5(), NULL);
97233294Sstas    EVP_DigestUpdate(ctx, data, len);
98233294Sstas    EVP_DigestUpdate(ctx, signmagic, strlen(signmagic) + 1);
99233294Sstas    EVP_DigestFinal_ex(ctx, key->signkey, NULL);
100178825Sdfr
101233294Sstas    EVP_DigestInit_ex(ctx, EVP_md5(), NULL);
102233294Sstas    EVP_DigestUpdate(ctx, data, len);
103233294Sstas    EVP_DigestUpdate(ctx, sealmagic, strlen(sealmagic) + 1);
104233294Sstas    EVP_DigestFinal_ex(ctx, out, NULL);
105233294Sstas    EVP_MD_CTX_destroy(ctx);
106178825Sdfr
107178825Sdfr    RC4_set_key(&key->sealkey, 16, out);
108178825Sdfr    if (sealsign)
109178825Sdfr	key->signsealkey = &key->sealkey;
110178825Sdfr}
111178825Sdfr
112178825Sdfr/*
113178825Sdfr *
114178825Sdfr */
115178825Sdfr
116178825Sdfrstatic OM_uint32
117178825Sdfrv1_sign_message(gss_buffer_t in,
118178825Sdfr		RC4_KEY *signkey,
119178825Sdfr		uint32_t seq,
120178825Sdfr		unsigned char out[16])
121178825Sdfr{
122178825Sdfr    unsigned char sigature[12];
123178825Sdfr    uint32_t crc;
124233294Sstas
125178825Sdfr    _krb5_crc_init_table();
126178825Sdfr    crc = _krb5_crc_update(in->value, in->length, 0);
127233294Sstas
128178825Sdfr    encode_le_uint32(0, &sigature[0]);
129178825Sdfr    encode_le_uint32(crc, &sigature[4]);
130178825Sdfr    encode_le_uint32(seq, &sigature[8]);
131233294Sstas
132178825Sdfr    encode_le_uint32(1, out); /* version */
133178825Sdfr    RC4(signkey, sizeof(sigature), sigature, out + 4);
134233294Sstas
135178825Sdfr    if (RAND_bytes(out + 4, 4) != 1)
136178825Sdfr	return GSS_S_UNAVAILABLE;
137233294Sstas
138178825Sdfr    return 0;
139178825Sdfr}
140178825Sdfr
141178825Sdfr
142178825Sdfrstatic OM_uint32
143178825Sdfrv2_sign_message(gss_buffer_t in,
144178825Sdfr		unsigned char signkey[16],
145178825Sdfr		RC4_KEY *sealkey,
146178825Sdfr		uint32_t seq,
147178825Sdfr		unsigned char out[16])
148178825Sdfr{
149178825Sdfr    unsigned char hmac[16];
150178825Sdfr    unsigned int hmaclen;
151178825Sdfr    HMAC_CTX c;
152178825Sdfr
153178825Sdfr    HMAC_CTX_init(&c);
154178825Sdfr    HMAC_Init_ex(&c, signkey, 16, EVP_md5(), NULL);
155233294Sstas
156178825Sdfr    encode_le_uint32(seq, hmac);
157178825Sdfr    HMAC_Update(&c, hmac, 4);
158178825Sdfr    HMAC_Update(&c, in->value, in->length);
159178825Sdfr    HMAC_Final(&c, hmac, &hmaclen);
160178825Sdfr    HMAC_CTX_cleanup(&c);
161178825Sdfr
162178825Sdfr    encode_le_uint32(1, &out[0]);
163178825Sdfr    if (sealkey)
164178825Sdfr	RC4(sealkey, 8, hmac, &out[4]);
165178825Sdfr    else
166178825Sdfr	memcpy(&out[4], hmac, 8);
167178825Sdfr
168178825Sdfr    memset(&out[12], 0, 4);
169178825Sdfr
170178825Sdfr    return GSS_S_COMPLETE;
171178825Sdfr}
172178825Sdfr
173178825Sdfrstatic OM_uint32
174178825Sdfrv2_verify_message(gss_buffer_t in,
175178825Sdfr		  unsigned char signkey[16],
176178825Sdfr		  RC4_KEY *sealkey,
177178825Sdfr		  uint32_t seq,
178178825Sdfr		  const unsigned char checksum[16])
179178825Sdfr{
180178825Sdfr    OM_uint32 ret;
181178825Sdfr    unsigned char out[16];
182178825Sdfr
183178825Sdfr    ret = v2_sign_message(in, signkey, sealkey, seq, out);
184178825Sdfr    if (ret)
185178825Sdfr	return ret;
186178825Sdfr
187178825Sdfr    if (memcmp(checksum, out, 16) != 0)
188178825Sdfr	return GSS_S_BAD_MIC;
189178825Sdfr
190178825Sdfr    return GSS_S_COMPLETE;
191233294Sstas}
192178825Sdfr
193178825Sdfrstatic OM_uint32
194178825Sdfrv2_seal_message(const gss_buffer_t in,
195178825Sdfr		unsigned char signkey[16],
196178825Sdfr		uint32_t seq,
197178825Sdfr		RC4_KEY *sealkey,
198178825Sdfr		gss_buffer_t out)
199178825Sdfr{
200178825Sdfr    unsigned char *p;
201178825Sdfr    OM_uint32 ret;
202178825Sdfr
203178825Sdfr    if (in->length + 16 < in->length)
204178825Sdfr	return EINVAL;
205178825Sdfr
206178825Sdfr    p = malloc(in->length + 16);
207178825Sdfr    if (p == NULL)
208178825Sdfr	return ENOMEM;
209178825Sdfr
210178825Sdfr    RC4(sealkey, in->length, in->value, p);
211178825Sdfr
212178825Sdfr    ret = v2_sign_message(in, signkey, sealkey, seq, &p[in->length]);
213178825Sdfr    if (ret) {
214178825Sdfr	free(p);
215178825Sdfr	return ret;
216178825Sdfr    }
217178825Sdfr
218178825Sdfr    out->value = p;
219178825Sdfr    out->length = in->length + 16;
220178825Sdfr
221178825Sdfr    return 0;
222178825Sdfr}
223178825Sdfr
224178825Sdfrstatic OM_uint32
225178825Sdfrv2_unseal_message(gss_buffer_t in,
226178825Sdfr		  unsigned char signkey[16],
227178825Sdfr		  uint32_t seq,
228178825Sdfr		  RC4_KEY *sealkey,
229178825Sdfr		  gss_buffer_t out)
230178825Sdfr{
231178825Sdfr    OM_uint32 ret;
232178825Sdfr
233178825Sdfr    if (in->length < 16)
234178825Sdfr	return GSS_S_BAD_MIC;
235178825Sdfr
236178825Sdfr    out->length = in->length - 16;
237178825Sdfr    out->value = malloc(out->length);
238178825Sdfr    if (out->value == NULL)
239178825Sdfr	return GSS_S_BAD_MIC;
240178825Sdfr
241178825Sdfr    RC4(sealkey, out->length, in->value, out->value);
242178825Sdfr
243178825Sdfr    ret = v2_verify_message(out, signkey, sealkey, seq,
244178825Sdfr			    ((const unsigned char *)in->value) + out->length);
245178825Sdfr    if (ret) {
246178825Sdfr	OM_uint32 junk;
247178825Sdfr	gss_release_buffer(&junk, out);
248178825Sdfr    }
249178825Sdfr    return ret;
250178825Sdfr}
251178825Sdfr
252178825Sdfr/*
253178825Sdfr *
254178825Sdfr */
255178825Sdfr
256178825Sdfr#define CTX_FLAGS_ISSET(_ctx,_flags) \
257178825Sdfr    (((_ctx)->flags & (_flags)) == (_flags))
258178825Sdfr
259178825Sdfr/*
260178825Sdfr *
261178825Sdfr */
262233294Sstas
263233294SstasOM_uint32 GSSAPI_CALLCONV
264233294Sstas_gss_ntlm_get_mic
265178825Sdfr           (OM_uint32 * minor_status,
266178825Sdfr            const gss_ctx_id_t context_handle,
267178825Sdfr            gss_qop_t qop_req,
268178825Sdfr            const gss_buffer_t message_buffer,
269178825Sdfr            gss_buffer_t message_token
270178825Sdfr           )
271178825Sdfr{
272178825Sdfr    ntlm_ctx ctx = (ntlm_ctx)context_handle;
273178825Sdfr    OM_uint32 junk;
274178825Sdfr
275233294Sstas    *minor_status = 0;
276178825Sdfr
277178825Sdfr    message_token->value = malloc(16);
278178825Sdfr    message_token->length = 16;
279178825Sdfr    if (message_token->value == NULL) {
280178825Sdfr	*minor_status = ENOMEM;
281178825Sdfr	return GSS_S_FAILURE;
282178825Sdfr    }
283178825Sdfr
284178825Sdfr    if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SIGN|NTLM_NEG_NTLM2_SESSION)) {
285178825Sdfr	OM_uint32 ret;
286178825Sdfr
287178825Sdfr	if ((ctx->status & STATUS_SESSIONKEY) == 0) {
288178825Sdfr	    gss_release_buffer(&junk, message_token);
289178825Sdfr	    return GSS_S_UNAVAILABLE;
290178825Sdfr	}
291178825Sdfr
292178825Sdfr	ret = v2_sign_message(message_buffer,
293178825Sdfr			      ctx->u.v2.send.signkey,
294178825Sdfr			      ctx->u.v2.send.signsealkey,
295178825Sdfr			      ctx->u.v2.send.seq++,
296178825Sdfr			      message_token->value);
297178825Sdfr	if (ret)
298178825Sdfr	    gss_release_buffer(&junk, message_token);
299178825Sdfr        return ret;
300178825Sdfr
301178825Sdfr    } else if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SIGN)) {
302178825Sdfr	OM_uint32 ret;
303178825Sdfr
304178825Sdfr	if ((ctx->status & STATUS_SESSIONKEY) == 0) {
305178825Sdfr	    gss_release_buffer(&junk, message_token);
306178825Sdfr	    return GSS_S_UNAVAILABLE;
307178825Sdfr	}
308178825Sdfr
309178825Sdfr	ret = v1_sign_message(message_buffer,
310178825Sdfr			      &ctx->u.v1.crypto_send.key,
311178825Sdfr			      ctx->u.v1.crypto_send.seq++,
312178825Sdfr			      message_token->value);
313178825Sdfr	if (ret)
314178825Sdfr	    gss_release_buffer(&junk, message_token);
315178825Sdfr        return ret;
316178825Sdfr
317178825Sdfr    } else if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_ALWAYS_SIGN)) {
318178825Sdfr	unsigned char *sigature;
319178825Sdfr
320178825Sdfr	sigature = message_token->value;
321178825Sdfr
322178825Sdfr	encode_le_uint32(1, &sigature[0]); /* version */
323178825Sdfr	encode_le_uint32(0, &sigature[4]);
324178825Sdfr	encode_le_uint32(0, &sigature[8]);
325178825Sdfr	encode_le_uint32(0, &sigature[12]);
326178825Sdfr
327178825Sdfr        return GSS_S_COMPLETE;
328178825Sdfr    }
329178825Sdfr    gss_release_buffer(&junk, message_token);
330178825Sdfr
331178825Sdfr    return GSS_S_UNAVAILABLE;
332178825Sdfr}
333178825Sdfr
334178825Sdfr/*
335178825Sdfr *
336178825Sdfr */
337178825Sdfr
338233294SstasOM_uint32 GSSAPI_CALLCONV
339178825Sdfr_gss_ntlm_verify_mic
340178825Sdfr           (OM_uint32 * minor_status,
341178825Sdfr            const gss_ctx_id_t context_handle,
342178825Sdfr            const gss_buffer_t message_buffer,
343178825Sdfr            const gss_buffer_t token_buffer,
344178825Sdfr            gss_qop_t * qop_state
345178825Sdfr	    )
346178825Sdfr{
347178825Sdfr    ntlm_ctx ctx = (ntlm_ctx)context_handle;
348178825Sdfr
349178825Sdfr    if (qop_state != NULL)
350178825Sdfr	*qop_state = GSS_C_QOP_DEFAULT;
351178825Sdfr    *minor_status = 0;
352178825Sdfr
353178825Sdfr    if (token_buffer->length != 16)
354178825Sdfr	return GSS_S_BAD_MIC;
355178825Sdfr
356178825Sdfr    if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SIGN|NTLM_NEG_NTLM2_SESSION)) {
357178825Sdfr	OM_uint32 ret;
358178825Sdfr
359178825Sdfr	if ((ctx->status & STATUS_SESSIONKEY) == 0)
360178825Sdfr	    return GSS_S_UNAVAILABLE;
361178825Sdfr
362178825Sdfr	ret = v2_verify_message(message_buffer,
363178825Sdfr				ctx->u.v2.recv.signkey,
364178825Sdfr				ctx->u.v2.recv.signsealkey,
365178825Sdfr				ctx->u.v2.recv.seq++,
366178825Sdfr				token_buffer->value);
367178825Sdfr	if (ret)
368178825Sdfr	    return ret;
369178825Sdfr
370178825Sdfr	return GSS_S_COMPLETE;
371178825Sdfr    } else if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SIGN)) {
372178825Sdfr
373178825Sdfr	unsigned char sigature[12];
374178825Sdfr	uint32_t crc, num;
375178825Sdfr
376178825Sdfr	if ((ctx->status & STATUS_SESSIONKEY) == 0)
377178825Sdfr	    return GSS_S_UNAVAILABLE;
378178825Sdfr
379178825Sdfr	decode_le_uint32(token_buffer->value, &num);
380178825Sdfr	if (num != 1)
381178825Sdfr	    return GSS_S_BAD_MIC;
382178825Sdfr
383178825Sdfr	RC4(&ctx->u.v1.crypto_recv.key, sizeof(sigature),
384178825Sdfr	    ((unsigned char *)token_buffer->value) + 4, sigature);
385178825Sdfr
386178825Sdfr	_krb5_crc_init_table();
387233294Sstas	crc = _krb5_crc_update(message_buffer->value,
388178825Sdfr			       message_buffer->length, 0);
389178825Sdfr	/* skip first 4 bytes in the encrypted checksum */
390178825Sdfr	decode_le_uint32(&sigature[4], &num);
391178825Sdfr	if (num != crc)
392178825Sdfr	    return GSS_S_BAD_MIC;
393178825Sdfr	decode_le_uint32(&sigature[8], &num);
394178825Sdfr	if (ctx->u.v1.crypto_recv.seq != num)
395178825Sdfr	    return GSS_S_BAD_MIC;
396178825Sdfr	ctx->u.v1.crypto_recv.seq++;
397178825Sdfr
398178825Sdfr        return GSS_S_COMPLETE;
399178825Sdfr    } else if (ctx->flags & NTLM_NEG_ALWAYS_SIGN) {
400178825Sdfr	uint32_t num;
401178825Sdfr	unsigned char *p;
402178825Sdfr
403178825Sdfr	p = (unsigned char*)(token_buffer->value);
404178825Sdfr
405178825Sdfr	decode_le_uint32(&p[0], &num); /* version */
406178825Sdfr	if (num != 1) return GSS_S_BAD_MIC;
407178825Sdfr	decode_le_uint32(&p[4], &num);
408178825Sdfr	if (num != 0) return GSS_S_BAD_MIC;
409178825Sdfr	decode_le_uint32(&p[8], &num);
410178825Sdfr	if (num != 0) return GSS_S_BAD_MIC;
411178825Sdfr	decode_le_uint32(&p[12], &num);
412178825Sdfr	if (num != 0) return GSS_S_BAD_MIC;
413178825Sdfr
414178825Sdfr        return GSS_S_COMPLETE;
415178825Sdfr    }
416178825Sdfr
417178825Sdfr    return GSS_S_UNAVAILABLE;
418178825Sdfr}
419178825Sdfr
420178825Sdfr/*
421178825Sdfr *
422178825Sdfr */
423178825Sdfr
424233294SstasOM_uint32 GSSAPI_CALLCONV
425178825Sdfr_gss_ntlm_wrap_size_limit (
426178825Sdfr            OM_uint32 * minor_status,
427178825Sdfr            const gss_ctx_id_t context_handle,
428178825Sdfr            int conf_req_flag,
429178825Sdfr            gss_qop_t qop_req,
430178825Sdfr            OM_uint32 req_output_size,
431178825Sdfr            OM_uint32 * max_input_size
432178825Sdfr           )
433178825Sdfr{
434178825Sdfr    ntlm_ctx ctx = (ntlm_ctx)context_handle;
435178825Sdfr
436178825Sdfr    *minor_status = 0;
437178825Sdfr
438178825Sdfr    if(ctx->flags & NTLM_NEG_SEAL) {
439178825Sdfr
440178825Sdfr	if (req_output_size < 16)
441178825Sdfr	    *max_input_size = 0;
442178825Sdfr	else
443178825Sdfr	    *max_input_size = req_output_size - 16;
444178825Sdfr
445178825Sdfr	return GSS_S_COMPLETE;
446178825Sdfr    }
447178825Sdfr
448178825Sdfr    return GSS_S_UNAVAILABLE;
449178825Sdfr}
450178825Sdfr
451178825Sdfr/*
452178825Sdfr *
453178825Sdfr */
454178825Sdfr
455233294SstasOM_uint32 GSSAPI_CALLCONV
456233294Sstas_gss_ntlm_wrap
457178825Sdfr(OM_uint32 * minor_status,
458178825Sdfr const gss_ctx_id_t context_handle,
459178825Sdfr int conf_req_flag,
460178825Sdfr gss_qop_t qop_req,
461178825Sdfr const gss_buffer_t input_message_buffer,
462178825Sdfr int * conf_state,
463178825Sdfr gss_buffer_t output_message_buffer
464178825Sdfr    )
465178825Sdfr{
466178825Sdfr    ntlm_ctx ctx = (ntlm_ctx)context_handle;
467178825Sdfr    OM_uint32 ret;
468178825Sdfr
469233294Sstas    *minor_status = 0;
470178825Sdfr    if (conf_state)
471178825Sdfr	*conf_state = 0;
472178825Sdfr    if (output_message_buffer == GSS_C_NO_BUFFER)
473178825Sdfr	return GSS_S_FAILURE;
474178825Sdfr
475233294Sstas
476178825Sdfr    if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SEAL|NTLM_NEG_NTLM2_SESSION)) {
477178825Sdfr
478178825Sdfr	return v2_seal_message(input_message_buffer,
479178825Sdfr			       ctx->u.v2.send.signkey,
480178825Sdfr			       ctx->u.v2.send.seq++,
481178825Sdfr			       &ctx->u.v2.send.sealkey,
482178825Sdfr			       output_message_buffer);
483178825Sdfr
484178825Sdfr    } else if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SEAL)) {
485178825Sdfr	gss_buffer_desc trailer;
486178825Sdfr	OM_uint32 junk;
487178825Sdfr
488178825Sdfr	output_message_buffer->length = input_message_buffer->length + 16;
489178825Sdfr	output_message_buffer->value = malloc(output_message_buffer->length);
490178825Sdfr	if (output_message_buffer->value == NULL) {
491178825Sdfr	    output_message_buffer->length = 0;
492178825Sdfr	    return GSS_S_FAILURE;
493178825Sdfr	}
494178825Sdfr
495178825Sdfr
496178825Sdfr	RC4(&ctx->u.v1.crypto_send.key, input_message_buffer->length,
497178825Sdfr	    input_message_buffer->value, output_message_buffer->value);
498233294Sstas
499178825Sdfr	ret = _gss_ntlm_get_mic(minor_status, context_handle,
500178825Sdfr				0, input_message_buffer,
501178825Sdfr				&trailer);
502178825Sdfr	if (ret) {
503178825Sdfr	    gss_release_buffer(&junk, output_message_buffer);
504178825Sdfr	    return ret;
505178825Sdfr	}
506178825Sdfr	if (trailer.length != 16) {
507178825Sdfr	    gss_release_buffer(&junk, output_message_buffer);
508178825Sdfr	    gss_release_buffer(&junk, &trailer);
509178825Sdfr	    return GSS_S_FAILURE;
510178825Sdfr	}
511233294Sstas	memcpy(((unsigned char *)output_message_buffer->value) +
512178825Sdfr	       input_message_buffer->length,
513178825Sdfr	       trailer.value, trailer.length);
514178825Sdfr	gss_release_buffer(&junk, &trailer);
515178825Sdfr
516178825Sdfr	return GSS_S_COMPLETE;
517178825Sdfr    }
518178825Sdfr
519178825Sdfr    return GSS_S_UNAVAILABLE;
520178825Sdfr}
521178825Sdfr
522178825Sdfr/*
523178825Sdfr *
524178825Sdfr */
525178825Sdfr
526233294SstasOM_uint32 GSSAPI_CALLCONV
527233294Sstas_gss_ntlm_unwrap
528178825Sdfr           (OM_uint32 * minor_status,
529178825Sdfr            const gss_ctx_id_t context_handle,
530178825Sdfr            const gss_buffer_t input_message_buffer,
531178825Sdfr            gss_buffer_t output_message_buffer,
532178825Sdfr            int * conf_state,
533178825Sdfr            gss_qop_t * qop_state
534178825Sdfr           )
535178825Sdfr{
536178825Sdfr    ntlm_ctx ctx = (ntlm_ctx)context_handle;
537178825Sdfr    OM_uint32 ret;
538178825Sdfr
539233294Sstas    *minor_status = 0;
540233294Sstas    output_message_buffer->value = NULL;
541233294Sstas    output_message_buffer->length = 0;
542233294Sstas
543178825Sdfr    if (conf_state)
544178825Sdfr	*conf_state = 0;
545178825Sdfr    if (qop_state)
546178825Sdfr	*qop_state = 0;
547178825Sdfr
548178825Sdfr    if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SEAL|NTLM_NEG_NTLM2_SESSION)) {
549178825Sdfr
550178825Sdfr	return v2_unseal_message(input_message_buffer,
551178825Sdfr				 ctx->u.v2.recv.signkey,
552178825Sdfr				 ctx->u.v2.recv.seq++,
553178825Sdfr				 &ctx->u.v2.recv.sealkey,
554178825Sdfr				 output_message_buffer);
555178825Sdfr
556178825Sdfr    } else if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SEAL)) {
557178825Sdfr
558178825Sdfr	gss_buffer_desc trailer;
559178825Sdfr	OM_uint32 junk;
560178825Sdfr
561178825Sdfr	if (input_message_buffer->length < 16)
562178825Sdfr	    return GSS_S_BAD_MIC;
563178825Sdfr
564178825Sdfr	output_message_buffer->length = input_message_buffer->length - 16;
565178825Sdfr	output_message_buffer->value = malloc(output_message_buffer->length);
566178825Sdfr	if (output_message_buffer->value == NULL) {
567178825Sdfr	    output_message_buffer->length = 0;
568178825Sdfr	    return GSS_S_FAILURE;
569178825Sdfr	}
570233294Sstas
571178825Sdfr	RC4(&ctx->u.v1.crypto_recv.key, output_message_buffer->length,
572178825Sdfr	    input_message_buffer->value, output_message_buffer->value);
573233294Sstas
574178825Sdfr	trailer.value = ((unsigned char *)input_message_buffer->value) +
575178825Sdfr	    output_message_buffer->length;
576178825Sdfr	trailer.length = 16;
577178825Sdfr
578178825Sdfr	ret = _gss_ntlm_verify_mic(minor_status, context_handle,
579178825Sdfr				   output_message_buffer,
580178825Sdfr				   &trailer, NULL);
581178825Sdfr	if (ret) {
582178825Sdfr	    gss_release_buffer(&junk, output_message_buffer);
583178825Sdfr	    return ret;
584178825Sdfr	}
585178825Sdfr
586178825Sdfr	return GSS_S_COMPLETE;
587178825Sdfr    }
588178825Sdfr
589178825Sdfr    return GSS_S_UNAVAILABLE;
590178825Sdfr}
591