1/*
2 * Copyright (c) 2006 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the Institute nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include "ntlm.h"
35
36uint32_t
37_krb5_crc_update (const char *p, size_t len, uint32_t res);
38void
39_krb5_crc_init_table(void);
40
41/*
42 *
43 */
44
45const char a2i_signmagic[] =
46    "session key to server-to-client signing key magic constant";
47const char a2i_sealmagic[] =
48    "session key to server-to-client sealing key magic constant";
49const char i2a_signmagic[] =
50    "session key to client-to-server signing key magic constant";
51const char i2a_sealmagic[] =
52    "session key to client-to-server sealing key magic constant";
53
54
55static void
56_gss_ntlm_set_key(struct ntlmv2_key *key, int acceptor, int sealsign,
57		  unsigned char *data, size_t len)
58{
59    unsigned char out[16];
60    CCDigestRef ctx;
61    const char *signmagic;
62    const char *sealmagic;
63
64    if (acceptor) {
65	signmagic = a2i_signmagic;
66	sealmagic = a2i_sealmagic;
67    } else {
68	signmagic = i2a_signmagic;
69	sealmagic = i2a_sealmagic;
70    }
71
72    key->seq = 0;
73
74    ctx = CCDigestCreate(kCCDigestMD5);
75    CCDigestUpdate(ctx, data, len);
76    CCDigestUpdate(ctx, signmagic, strlen(signmagic) + 1);
77    CCDigestFinal(ctx, key->signkey);
78
79    CCDigestReset(ctx);
80    CCDigestUpdate(ctx, data, len);
81    CCDigestUpdate(ctx, sealmagic, strlen(sealmagic) + 1);
82    CCDigestFinal(ctx, out);
83    CCDigestDestroy(ctx);
84
85    EVP_CIPHER_CTX_cleanup(&key->sealkey);
86
87    EVP_CipherInit_ex(&key->sealkey, EVP_rc4(), NULL, out, NULL, 1);
88    if (sealsign) {
89	key->signsealkey = &key->sealkey;
90    }
91}
92
93/*
94 * Set (or reset) keys
95 */
96
97void
98_gss_ntlm_set_keys(ntlm_ctx ctx)
99{
100    int acceptor = (ctx->status & STATUS_CLIENT) ? 0 : 1;
101
102    if (ctx->sessionkey.length == 0)
103	return;
104
105    ctx->status |= STATUS_SESSIONKEY;
106
107    if (ctx->flags & NTLM_NEG_SEAL)
108	ctx->gssflags |= GSS_C_CONF_FLAG;
109    if (ctx->flags & (NTLM_NEG_SIGN|NTLM_NEG_ALWAYS_SIGN))
110	ctx->gssflags |= GSS_C_INTEG_FLAG;
111
112    if (ctx->flags & NTLM_NEG_NTLM2_SESSION) {
113	_gss_ntlm_set_key(&ctx->u.v2.send, acceptor,
114			  (ctx->flags & NTLM_NEG_KEYEX),
115			  ctx->sessionkey.data,
116			  ctx->sessionkey.length);
117	_gss_ntlm_set_key(&ctx->u.v2.recv, !acceptor,
118			  (ctx->flags & NTLM_NEG_KEYEX),
119			  ctx->sessionkey.data,
120			  ctx->sessionkey.length);
121    } else {
122	EVP_CIPHER_CTX_cleanup(&ctx->u.v1.crypto_send.key);
123	EVP_CIPHER_CTX_cleanup(&ctx->u.v1.crypto_recv.key);
124
125	EVP_CipherInit_ex(&ctx->u.v1.crypto_send.key, EVP_rc4(), NULL,
126			  ctx->sessionkey.data, NULL, 1);
127	EVP_CipherInit_ex(&ctx->u.v1.crypto_recv.key, EVP_rc4(), NULL,
128			  ctx->sessionkey.data, NULL, 1);
129    }
130}
131
132void
133_gss_ntlm_destroy_crypto(ntlm_ctx ctx)
134{
135    if ((ctx->status & STATUS_SESSIONKEY) == 0)
136	return;
137
138    if (ctx->flags & NTLM_NEG_NTLM2_SESSION) {
139	EVP_CIPHER_CTX_cleanup(&ctx->u.v2.send.sealkey);
140	EVP_CIPHER_CTX_cleanup(&ctx->u.v2.recv.sealkey);
141    } else {
142	EVP_CIPHER_CTX_cleanup(&ctx->u.v1.crypto_send.key);
143	EVP_CIPHER_CTX_cleanup(&ctx->u.v1.crypto_recv.key);
144    }
145}
146
147
148/*
149 *
150 */
151
152static OM_uint32
153v1_sign_message(EVP_CIPHER_CTX *signkey,
154		uint32_t seq,
155		gss_iov_buffer_t trailer,
156                gss_iov_buffer_desc *iov,
157                int iov_count)
158{
159    unsigned char *out = trailer->buffer.value;
160    unsigned char signature[12];
161    uint32_t crc = 0;
162    int i;
163
164    _krb5_crc_init_table();
165
166    for (i = 0; i < iov_count; i++) {
167        gss_iov_buffer_t iovp = &iov[i];
168
169        switch (GSS_IOV_BUFFER_TYPE(iovp->type)) {
170        case GSS_IOV_BUFFER_TYPE_DATA:
171        case GSS_IOV_BUFFER_TYPE_PADDING:
172        case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
173            crc = _krb5_crc_update(iovp->buffer.value, iovp->buffer.length, crc);
174            break;
175        default:
176            break;
177        }
178    }
179
180    _gss_mg_encode_le_uint32(0, &signature[0]);
181    _gss_mg_encode_le_uint32(crc, &signature[4]);
182    _gss_mg_encode_le_uint32(seq, &signature[8]);
183
184    _gss_mg_encode_le_uint32(1, out); /* version */
185
186    EVP_Cipher(signkey, out + 4, signature, sizeof(signature));
187
188    if (CCRandomCopyBytes(kCCRandomDefault, out + 4, 4))
189	return GSS_S_UNAVAILABLE;
190
191    return 0;
192}
193
194
195static OM_uint32
196v2_sign_message(unsigned char signkey[16],
197		EVP_CIPHER_CTX *sealkey,
198		uint32_t seq,
199		gss_iov_buffer_t trailer,
200                gss_iov_buffer_desc *iov,
201                int iov_count)
202{
203    unsigned char *out = trailer->buffer.value;
204    unsigned char hmac[16];
205    CCHmacContext c;
206    int i;
207
208    assert(trailer->buffer.length == 16);
209
210    CCHmacInit(&c, kCCHmacAlgMD5, signkey, 16);
211
212    _gss_mg_encode_le_uint32(seq, hmac);
213    CCHmacUpdate(&c, hmac, 4);
214    for (i = 0; i < iov_count; i++) {
215        gss_iov_buffer_t iovp = &iov[i];
216
217        /*
218         * We include empty buffers because NTLM2 always does
219         * DCE RPC header signing regardless of whether it was
220         * negotiated at bind time. The DCE RPC runtime will
221         * submit EMPTY header buffers when signing is disabled.
222         */
223        switch (GSS_IOV_BUFFER_TYPE(iovp->type)) {
224        case GSS_IOV_BUFFER_TYPE_EMPTY:
225        case GSS_IOV_BUFFER_TYPE_DATA:
226        case GSS_IOV_BUFFER_TYPE_PADDING:
227        case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
228            CCHmacUpdate(&c, iovp->buffer.value, iovp->buffer.length);
229            break;
230        default:
231            break;
232        }
233    }
234    CCHmacFinal(&c, hmac);
235    memset(&c, 0, sizeof(c));
236
237    _gss_mg_encode_le_uint32(1, &out[0]);
238    if (sealkey)
239	EVP_Cipher(sealkey, out + 4, hmac, 8);
240    else
241	memcpy(&out[4], hmac, 8);
242
243    memset(&out[12], 0, 4);
244
245    return GSS_S_COMPLETE;
246}
247
248static OM_uint32
249v2_verify_message(unsigned char signkey[16],
250		  EVP_CIPHER_CTX *sealkey,
251		  uint32_t seq,
252		  gss_iov_buffer_t trailer,
253                  gss_iov_buffer_desc *iov,
254                  int iov_count)
255{
256    OM_uint32 ret;
257    unsigned char outbuf[16];
258    gss_iov_buffer_desc out;
259
260    if (trailer->buffer.length != 16)
261	return GSS_S_BAD_MIC;
262
263    _gss_mg_decode_be_uint32((uint8_t *)trailer->buffer.value + 12, &seq);
264
265    out.type = GSS_IOV_BUFFER_TYPE_TRAILER;
266    out.buffer.length = sizeof(outbuf);
267    out.buffer.value = outbuf;
268
269    ret = v2_sign_message(signkey, sealkey, seq, &out, iov, iov_count);
270    if (ret)
271	return ret;
272
273    if (ct_memcmp(trailer->buffer.value, outbuf, 16))
274	return GSS_S_BAD_MIC;
275
276    return GSS_S_COMPLETE;
277}
278
279static OM_uint32
280v2_seal_message(unsigned char signkey[16],
281		uint32_t seq,
282		EVP_CIPHER_CTX *sealkey,
283                gss_iov_buffer_t trailer,
284		gss_iov_buffer_desc *iov,
285                int iov_count)
286{
287    OM_uint32 ret;
288    int i;
289
290    for (i = 0; i < iov_count; i++) {
291        gss_iov_buffer_t iovp = &iov[i];
292
293        switch (GSS_IOV_BUFFER_TYPE(iovp->type)) {
294        case GSS_IOV_BUFFER_TYPE_DATA:
295        case GSS_IOV_BUFFER_TYPE_PADDING:
296	    EVP_Cipher(sealkey, iovp->buffer.value, iovp->buffer.value,
297		       iovp->buffer.length);
298            break;
299        default:
300            break;
301        }
302    }
303
304    assert(trailer->buffer.length == 16);
305
306    ret = v2_sign_message(signkey, sealkey, seq, trailer, iov, iov_count);
307
308    return ret;
309}
310
311static OM_uint32
312v2_unseal_message(unsigned char signkey[16],
313		  uint32_t seq,
314		  EVP_CIPHER_CTX *sealkey,
315                  gss_iov_buffer_t trailer,
316                  gss_iov_buffer_desc *iov,
317                  int iov_count)
318{
319    OM_uint32 ret;
320    int i;
321
322    for (i = 0; i < iov_count; i++) {
323        gss_iov_buffer_t iovp = &iov[i];
324
325        switch (GSS_IOV_BUFFER_TYPE(iovp->type)) {
326        case GSS_IOV_BUFFER_TYPE_DATA:
327        case GSS_IOV_BUFFER_TYPE_PADDING:
328	    EVP_Cipher(sealkey, iovp->buffer.value, iovp->buffer.value,
329		       iovp->buffer.length);
330            break;
331        default:
332            break;
333        }
334    }
335
336    ret = v2_verify_message(signkey, sealkey, seq,
337                            trailer, iov, iov_count);
338
339    return ret;
340}
341
342/*
343 *
344 */
345
346#define CTX_FLAGS_ISSET(_ctx,_flags) \
347    (((_ctx)->flags & (_flags)) == (_flags))
348
349/*
350 *
351 */
352
353static OM_uint32 get_mic_iov
354           (OM_uint32 * minor_status,
355            const gss_ctx_id_t context_handle,
356            gss_qop_t qop_req,
357            gss_iov_buffer_t trailer,
358            gss_iov_buffer_desc *iov,
359            int iov_count
360           )
361{
362    ntlm_ctx ctx = (ntlm_ctx)context_handle;
363
364    *minor_status = 0;
365
366    assert(trailer->buffer.length == 16);
367    assert(trailer->buffer.value != NULL);
368
369    if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SIGN|NTLM_NEG_NTLM2_SESSION)) {
370	OM_uint32 ret;
371
372	if ((ctx->status & STATUS_SESSIONKEY) == 0)
373	    return GSS_S_UNAVAILABLE;
374
375	ret = v2_sign_message(ctx->u.v2.send.signkey,
376			      ctx->u.v2.send.signsealkey,
377			      ctx->u.v2.send.seq++,
378			      trailer, iov, iov_count);
379        return ret;
380
381    } else if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SIGN)) {
382	OM_uint32 ret;
383
384	if ((ctx->status & STATUS_SESSIONKEY) == 0)
385	    return GSS_S_UNAVAILABLE;
386
387	ret = v1_sign_message(&ctx->u.v1.crypto_send.key,
388			      ctx->u.v1.crypto_send.seq++,
389			      trailer, iov, iov_count);
390        return ret;
391
392    } else if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_ALWAYS_SIGN)) {
393	unsigned char *signature;
394
395	signature = trailer->buffer.value;
396
397	_gss_mg_encode_le_uint32(1, &signature[0]); /* version */
398	_gss_mg_encode_le_uint32(0, &signature[4]);
399	_gss_mg_encode_le_uint32(0, &signature[8]);
400	_gss_mg_encode_le_uint32(0, &signature[12]);
401
402        return GSS_S_COMPLETE;
403    }
404
405    return GSS_S_UNAVAILABLE;
406}
407
408OM_uint32 _gss_ntlm_get_mic
409           (OM_uint32 * minor_status,
410            const gss_ctx_id_t context_handle,
411            gss_qop_t qop_req,
412            const gss_buffer_t message_buffer,
413            gss_buffer_t message_token
414           )
415{
416    gss_iov_buffer_desc iov[2];
417    OM_uint32 ret, junk;
418
419    iov[0].type = GSS_IOV_BUFFER_TYPE_DATA;
420    iov[0].buffer = *message_buffer;
421
422    iov[1].type = GSS_IOV_BUFFER_TYPE_TRAILER;
423    iov[1].buffer.length = 16;
424    iov[1].buffer.value = malloc(iov[1].buffer.length);
425    if (iov[1].buffer.value == NULL) {
426        *minor_status = ENOMEM;
427        return GSS_S_FAILURE;
428    }
429
430    ret = get_mic_iov(minor_status, context_handle, qop_req,
431                      &iov[1], iov, 1);
432
433    if (ret)
434        gss_release_buffer(&junk, &iov[1].buffer);
435    else
436        *message_token = iov[1].buffer;
437
438    return ret;
439}
440
441/*
442 *
443 */
444
445static OM_uint32
446verify_mic_iov
447           (OM_uint32 * minor_status,
448            const gss_ctx_id_t context_handle,
449            gss_iov_buffer_t trailer,
450            gss_qop_t * qop_state,
451            gss_iov_buffer_desc *iov,
452            int iov_count
453	    )
454{
455    ntlm_ctx ctx = (ntlm_ctx)context_handle;
456
457    if (qop_state != NULL)
458	*qop_state = GSS_C_QOP_DEFAULT;
459    *minor_status = 0;
460
461    if (trailer->buffer.length != 16)
462	return GSS_S_BAD_MIC;
463
464    if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SIGN|NTLM_NEG_NTLM2_SESSION)) {
465	OM_uint32 ret;
466
467	if ((ctx->status & STATUS_SESSIONKEY) == 0)
468	    return GSS_S_UNAVAILABLE;
469
470	ret = v2_verify_message(ctx->u.v2.recv.signkey,
471				ctx->u.v2.recv.signsealkey,
472				0,
473				trailer, iov, iov_count);
474	if (ret)
475	    return ret;
476
477	return GSS_S_COMPLETE;
478    } else if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SIGN)) {
479	unsigned char signature[12];
480	uint32_t crc = 0, num;
481        int i;
482
483	if ((ctx->status & STATUS_SESSIONKEY) == 0)
484	    return GSS_S_UNAVAILABLE;
485
486	_gss_mg_decode_le_uint32(trailer->buffer.value, &num);
487	if (num != 1)
488	    return GSS_S_BAD_MIC;
489
490	EVP_Cipher(&ctx->u.v1.crypto_recv.key, signature,
491		   ((unsigned char *)trailer->buffer.value) + 4,
492		   sizeof(signature));
493
494	_krb5_crc_init_table();
495
496        for (i = 0; i < iov_count; i++) {
497            gss_iov_buffer_t iovp = &iov[i];
498
499            switch (GSS_IOV_BUFFER_TYPE(iovp->type)) {
500            case GSS_IOV_BUFFER_TYPE_DATA:
501            case GSS_IOV_BUFFER_TYPE_PADDING:
502            case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
503                crc = _krb5_crc_update(iovp->buffer.value,
504                                       iovp->buffer.length, crc);
505                break;
506            default:
507                break;
508            }
509        }
510
511	/* skip first 4 bytes in the encrypted checksum */
512	_gss_mg_decode_le_uint32(&signature[4], &num);
513	if (num != crc)
514	    return GSS_S_BAD_MIC;
515	_gss_mg_decode_le_uint32(&signature[8], &num);
516	if (ctx->u.v1.crypto_recv.seq != num)
517	    return GSS_S_BAD_MIC;
518	ctx->u.v1.crypto_recv.seq++;
519
520        return GSS_S_COMPLETE;
521    } else if (ctx->flags & NTLM_NEG_ALWAYS_SIGN) {
522	uint32_t num;
523	unsigned char *p;
524
525	p = (unsigned char*)(trailer->buffer.value);
526
527	_gss_mg_decode_le_uint32(&p[0], &num); /* version */
528	if (num != 1) return GSS_S_BAD_MIC;
529	_gss_mg_decode_le_uint32(&p[4], &num);
530	if (num != 0) return GSS_S_BAD_MIC;
531	_gss_mg_decode_le_uint32(&p[8], &num);
532	if (num != 0) return GSS_S_BAD_MIC;
533	_gss_mg_decode_le_uint32(&p[12], &num);
534	if (num != 0) return GSS_S_BAD_MIC;
535
536        return GSS_S_COMPLETE;
537    }
538
539    return GSS_S_UNAVAILABLE;
540}
541
542OM_uint32
543_gss_ntlm_verify_mic
544           (OM_uint32 * minor_status,
545            const gss_ctx_id_t context_handle,
546            const gss_buffer_t message_buffer,
547            const gss_buffer_t token_buffer,
548            gss_qop_t * qop_state
549	    )
550{
551    gss_iov_buffer_desc iov[2];
552
553    iov[0].type = GSS_IOV_BUFFER_TYPE_DATA;
554    iov[0].buffer = *message_buffer;
555
556    iov[1].type = GSS_IOV_BUFFER_TYPE_TRAILER;
557    iov[1].buffer = *token_buffer;
558
559    return verify_mic_iov(minor_status, context_handle,
560                          &iov[1], qop_state, iov, 1);
561}
562
563/*
564 *
565 */
566
567OM_uint32
568_gss_ntlm_wrap_size_limit (
569            OM_uint32 * minor_status,
570            const gss_ctx_id_t context_handle,
571            int conf_req_flag,
572            gss_qop_t qop_req,
573            OM_uint32 req_output_size,
574            OM_uint32 * max_input_size
575           )
576{
577    ntlm_ctx ctx = (ntlm_ctx)context_handle;
578
579    *minor_status = 0;
580
581    if(ctx->flags & NTLM_NEG_SEAL) {
582
583	if (req_output_size < 16)
584	    *max_input_size = 0;
585	else
586	    *max_input_size = req_output_size - 16;
587
588	return GSS_S_COMPLETE;
589    }
590
591    return GSS_S_UNAVAILABLE;
592}
593
594/*
595 *
596 */
597
598OM_uint32 _gss_ntlm_wrap_iov
599(OM_uint32 * minor_status,
600 const gss_ctx_id_t context_handle,
601 int conf_req_flag,
602 gss_qop_t qop_req,
603 int * conf_state,
604 gss_iov_buffer_desc *iov,
605 int iov_count
606    )
607{
608    ntlm_ctx ctx = (ntlm_ctx)context_handle;
609    OM_uint32 ret;
610    gss_iov_buffer_t trailer;
611
612    *minor_status = 0;
613    if (conf_state)
614	*conf_state = 0;
615    if (iov == GSS_C_NO_IOV_BUFFER)
616	return GSS_S_FAILURE;
617
618    /* TRAILER for normal protocols, HEADER for DCE */
619    trailer = _gss_mg_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
620    if (trailer == NULL) {
621        trailer = _gss_mg_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
622        if (trailer == NULL) {
623	    *minor_status = HNTLM_ERR_MISSING_BUFFER;
624	    return gss_mg_set_error_string(GSS_NTLM_MECHANISM, GSS_S_FAILURE,
625					   HNTLM_ERR_MISSING_BUFFER,
626					   "iov header buffer missing");
627        }
628    }
629    if (GSS_IOV_BUFFER_FLAGS(trailer->type) & GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE) {
630        ret = _gss_mg_allocate_buffer(minor_status, trailer, 16);
631        if (ret)
632            return ret;
633    } else if (trailer->buffer.length < 16) {
634        *minor_status = KRB5_BAD_MSIZE;
635        return GSS_S_FAILURE;
636    } else {
637        trailer->buffer.length = 16;
638    }
639
640    if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SEAL|NTLM_NEG_NTLM2_SESSION)) {
641
642	return v2_seal_message(ctx->u.v2.send.signkey,
643			       ctx->u.v2.send.seq++,
644			       &ctx->u.v2.send.sealkey,
645			       trailer, iov, iov_count);
646
647    } else if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SEAL)) {
648        int i;
649
650        for (i = 0; i < iov_count; i++) {
651            gss_iov_buffer_t iovp = &iov[i];
652
653            switch (GSS_IOV_BUFFER_TYPE(iovp->type)) {
654            case GSS_IOV_BUFFER_TYPE_DATA:
655            case GSS_IOV_BUFFER_TYPE_PADDING:
656		EVP_Cipher(&ctx->u.v1.crypto_send.key,
657			   iovp->buffer.value, iovp->buffer.value,
658			   iovp->buffer.length);
659                break;
660            default:
661                break;
662            }
663        }
664
665	ret = get_mic_iov(minor_status, context_handle,
666				0, trailer, iov, iov_count);
667
668	return ret;
669    }
670
671    return GSS_S_UNAVAILABLE;
672}
673
674OM_uint32 _gss_ntlm_wrap
675(OM_uint32 * minor_status,
676 const gss_ctx_id_t context_handle,
677 int conf_req_flag,
678 gss_qop_t qop_req,
679 const gss_buffer_t input_message_buffer,
680 int * conf_state,
681 gss_buffer_t output_message_buffer)
682{
683    gss_iov_buffer_desc iov[2];
684    OM_uint32 ret;
685
686    output_message_buffer->length = input_message_buffer->length + 16;
687    output_message_buffer->value = malloc(output_message_buffer->length);
688    if (output_message_buffer->value == NULL) {
689        *minor_status = ENOMEM;
690        return GSS_S_FAILURE;
691    }
692
693    iov[0].type = GSS_IOV_BUFFER_TYPE_DATA;
694    iov[0].buffer.length = input_message_buffer->length;
695    iov[0].buffer.value = output_message_buffer->value;
696    memcpy(iov[0].buffer.value, input_message_buffer->value,
697           input_message_buffer->length);
698
699    iov[1].type = GSS_IOV_BUFFER_TYPE_TRAILER;
700    iov[1].buffer.length = 16;
701    iov[1].buffer.value = (unsigned char *)output_message_buffer->value + 16;
702
703    ret = _gss_ntlm_wrap_iov(minor_status, context_handle,
704                             conf_req_flag, qop_req,
705                             conf_state, iov, sizeof(iov)/sizeof(iov[0]));
706    if (GSS_ERROR(ret)) {
707        OM_uint32 tmp;
708        gss_release_buffer(&tmp, output_message_buffer);
709    }
710
711    return ret;
712}
713
714/*
715 *
716 */
717
718OM_uint32 _gss_ntlm_unwrap_iov
719           (OM_uint32 * minor_status,
720            const gss_ctx_id_t context_handle,
721            int * conf_state,
722            gss_qop_t * qop_state,
723            gss_iov_buffer_desc *iov,
724            int iov_count
725           )
726{
727    ntlm_ctx ctx = (ntlm_ctx)context_handle;
728    OM_uint32 ret;
729    gss_iov_buffer_t trailer;
730
731    *minor_status = 0;
732
733    if (conf_state)
734	*conf_state = 0;
735    if (qop_state)
736	*qop_state = 0;
737
738    /* TRAILER for normal protocols, HEADER for DCE */
739    trailer = _gss_mg_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
740    if (trailer == NULL) {
741        trailer = _gss_mg_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
742        if (trailer == NULL) {
743	    *minor_status = HNTLM_ERR_MISSING_BUFFER;
744	    return gss_mg_set_error_string(GSS_NTLM_MECHANISM, GSS_S_FAILURE,
745					   HNTLM_ERR_MISSING_BUFFER,
746					   "iov tailer buffer missing");
747        }
748    }
749
750    if (trailer->buffer.length < 16)
751        return GSS_S_BAD_MIC;
752
753    if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SEAL|NTLM_NEG_NTLM2_SESSION)) {
754
755	return v2_unseal_message(ctx->u.v2.recv.signkey,
756				 ctx->u.v2.recv.seq++,
757				 &ctx->u.v2.recv.sealkey,
758				 trailer,
759				 iov,
760				 iov_count);
761
762    } else if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SEAL)) {
763
764        int i;
765
766        for (i = 0; i < iov_count; i++) {
767            gss_iov_buffer_t iovp = &iov[i];
768
769            switch (GSS_IOV_BUFFER_TYPE(iovp->type)) {
770            case GSS_IOV_BUFFER_TYPE_DATA:
771            case GSS_IOV_BUFFER_TYPE_PADDING:
772		EVP_Cipher(&ctx->u.v1.crypto_recv.key,
773			   iovp->buffer.value, iovp->buffer.value,
774			   iovp->buffer.length);
775                break;
776            default:
777                break;
778            }
779        }
780
781	ret = verify_mic_iov(minor_status, context_handle,
782                             trailer, NULL, iov, iov_count);
783
784	return ret;
785    }
786
787    return GSS_S_UNAVAILABLE;
788}
789
790OM_uint32 _gss_ntlm_unwrap
791           (OM_uint32 * minor_status,
792            const gss_ctx_id_t context_handle,
793            const gss_buffer_t input_message_buffer,
794            gss_buffer_t output_message_buffer,
795            int * conf_state,
796            gss_qop_t * qop_state
797           )
798{
799    gss_iov_buffer_desc iov[2];
800    OM_uint32 ret;
801
802    if (input_message_buffer->length < 16)
803        return GSS_S_DEFECTIVE_TOKEN;
804
805    output_message_buffer->length = input_message_buffer->length - 16;
806    output_message_buffer->value = malloc(output_message_buffer->length);
807    if (output_message_buffer->value == NULL) {
808        *minor_status = ENOMEM;
809        return GSS_S_FAILURE;
810    }
811    memcpy(output_message_buffer->value, input_message_buffer->value,
812           output_message_buffer->length);
813
814    iov[0].type = GSS_IOV_BUFFER_TYPE_DATA;
815    iov[0].buffer = *output_message_buffer;
816
817    iov[1].type = GSS_IOV_BUFFER_TYPE_TRAILER;
818    iov[1].buffer.value = (unsigned char *)input_message_buffer->value +
819                          input_message_buffer->length - 16;
820    iov[1].buffer.length = 16;
821
822    ret = _gss_ntlm_unwrap_iov(minor_status, context_handle,
823                               conf_state, qop_state, iov,
824                               sizeof(iov)/sizeof(iov[0]));
825    if (GSS_ERROR(ret)) {
826        OM_uint32 tmp;
827        gss_release_buffer(&tmp, output_message_buffer);
828    }
829
830    return ret;
831}
832
833OM_uint32
834_gss_ntlm_wrap_iov_length(OM_uint32 * minor_status,
835                          gss_ctx_id_t context_handle,
836                          int conf_req_flag,
837                          gss_qop_t qop_req,
838                          int *conf_state,
839                          gss_iov_buffer_desc *iov,
840                          int iov_count)
841{
842    gss_iov_buffer_t iovp;
843    OM_uint32 ctype;
844
845    /* DCE puts the trailer in the HEADER, other protocols in TRAILER. */
846    iovp = _gss_mg_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
847    if (iovp == NULL) {
848        iovp = _gss_mg_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
849        if (iovp == NULL) {
850	    *minor_status = HNTLM_ERR_MISSING_BUFFER;
851	    return gss_mg_set_error_string(GSS_NTLM_MECHANISM, GSS_S_FAILURE,
852					   HNTLM_ERR_MISSING_BUFFER,
853					   "iov header buffer missing");
854        } else
855            ctype = GSS_IOV_BUFFER_TYPE_TRAILER;
856    } else
857        ctype = GSS_IOV_BUFFER_TYPE_HEADER;
858
859    iovp->buffer.length = 16;
860
861    iovp = _gss_mg_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
862    if (iovp != NULL)
863        iovp->buffer.length = 0;
864
865    /* No HEADER if we have a TRAILER and vice versa */
866    iovp = _gss_mg_find_buffer(iov, iov_count, ctype);
867    if (iovp != NULL)
868        iovp->buffer.length = 0;
869
870    if (conf_state != NULL)
871        *conf_state = conf_req_flag;
872
873    *minor_status = 0;
874    return GSS_S_COMPLETE;
875}
876
877
878void
879_gss_ntlm_debug_hex(int level, const char *name, const void *data, size_t size)
880{
881    char *hex;
882
883    if (!_gss_mg_log_level(level))
884	return;
885
886    if (hex_encode(data, size, &hex) < 0)
887	return;
888
889    _gss_mg_log(level, "%s %s", name, hex);
890    free(hex);
891}
892
893void
894_gss_ntlm_debug_key(int level, const char *name, const void *data, size_t size)
895{
896    char *hex;
897
898    /**
899     * Only print the first 2 bytes though since we really don't want
900     * the full key sprinkled though logs.
901     */
902    size = min(size, 2);
903
904    if (!_gss_mg_log_level(level))
905	return;
906
907    if (hex_encode(data, size, &hex) < 0)
908	return;
909
910    _gss_mg_log(level, "%s %s", name, hex);
911    memset(hex, 0, strlen(hex));
912    free(hex);
913}
914