1/*
2 * Copyright (c) 2010 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Portions Copyright (c) 2010 Apple Inc. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the Institute nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include "netlogon.h"
37
38static uint8_t zeros[4];
39
40static void
41_netlogon_encode_sequence_number(uint64_t SequenceNumber, uint8_t *p,
42                                 int initiatorFlag)
43{
44    uint32_t LowPart, HighPart;
45
46    LowPart  = (SequenceNumber >> 0 ) & 0xFFFFFFFF;
47    HighPart = (SequenceNumber >> 32) & 0xFFFFFFFF;
48
49    _gss_mg_encode_be_uint32(LowPart,  &p[0]);
50    _gss_mg_encode_be_uint32(HighPart, &p[4]);
51
52    if (initiatorFlag)
53        p[4] |= 0x80;
54}
55
56static int
57_netlogon_decode_sequence_number(void *ptr, uint64_t *n,
58                                 int initiatorFlag)
59{
60    uint8_t *p = ptr;
61    uint32_t LowPart, HighPart;
62    int gotInitiatorFlag;
63
64    gotInitiatorFlag = (p[4] & 0x80) != 0;
65    if (gotInitiatorFlag != initiatorFlag)
66        return -1;
67
68    p[4] &= 0x7F; /* clear initiator bit */
69
70    _gss_mg_decode_be_uint32(&p[0], &LowPart);
71    _gss_mg_decode_be_uint32(&p[4], &HighPart);
72
73    *n = (LowPart << 0) | ((uint64_t)HighPart << 32);
74
75    return 0;
76}
77
78static inline size_t
79_netlogon_checksum_length(NL_AUTH_SIGNATURE *sig)
80{
81#if 0
82    return (sig->SignatureAlgorithm == NL_SIGN_ALG_SHA256) ? 32 : 8;
83#else
84    /* Owing to a bug in Windows it always uses the old value */
85    return 8;
86#endif
87}
88
89static inline size_t
90_netlogon_signature_length(uint16_t alg, int conf_req_flag)
91{
92    return NL_AUTH_SIGNATURE_COMMON_LENGTH +
93        (alg == NL_SIGN_ALG_SHA256 ? 32 : 8) +
94        (conf_req_flag ? 8 : 0);
95}
96
97static inline uint8_t *
98_netlogon_confounder(NL_AUTH_SIGNATURE *sig)
99{
100    size_t cksumlen = _netlogon_checksum_length(sig);
101
102    return &sig->Checksum[cksumlen];
103}
104
105static int
106_netlogon_encode_NL_AUTH_SIGNATURE(NL_AUTH_SIGNATURE *sig,
107                                   uint8_t *p, size_t len)
108{
109    *p++ = (sig->SignatureAlgorithm >> 0) & 0xFF;
110    *p++ = (sig->SignatureAlgorithm >> 8) & 0xFF;
111    *p++ = (sig->SealAlgorithm      >> 0) & 0xFF;
112    *p++ = (sig->SealAlgorithm      >> 8) & 0xFF;
113    *p++ = (sig->Pad                >> 0) & 0xFF;
114    *p++ = (sig->Pad                >> 8) & 0xFF;
115    *p++ = (sig->Flags              >> 0) & 0xFF;
116    *p++ = (sig->Flags              >> 8) & 0xFF;
117
118    if (len > NL_AUTH_SIGNATURE_HEADER_LENGTH) {
119        memcpy(p, sig->SequenceNumber, 8);
120        p += 8;
121    }
122
123    if (len > NL_AUTH_SIGNATURE_COMMON_LENGTH) {
124        size_t cksumlen = _netlogon_checksum_length(sig);
125
126        memcpy(p, sig->Checksum, cksumlen);
127        p += cksumlen;
128
129        /* Confounder, if present, is immediately after checksum */
130        if (sig->SealAlgorithm != NL_SEAL_ALG_NONE) {
131            memcpy(p, &sig->Checksum[cksumlen], 8);
132        }
133    }
134
135    return 0;
136}
137
138static int
139_netlogon_decode_NL_AUTH_SIGNATURE(const uint8_t *ptr,
140                                   size_t len,
141                                   NL_AUTH_SIGNATURE *sig)
142{
143    const uint8_t *p = ptr;
144    size_t cksumlen;
145
146    if (len < NL_AUTH_SIGNATURE_COMMON_LENGTH)
147        return KRB5_BAD_MSIZE;
148
149    sig->SignatureAlgorithm = (p[0] << 0) | (p[1] << 8);
150    sig->SealAlgorithm      = (p[2] << 0) | (p[3] << 8);
151    sig->Pad                = (p[4] << 0) | (p[5] << 8);
152    sig->Flags              = (p[6] << 0) | (p[7] << 8);
153    p += 8;
154
155    memcpy(sig->SequenceNumber, p, 8);
156    p += 8;
157
158    /* Validate signature algorithm is known and matches enctype */
159    switch (sig->SignatureAlgorithm) {
160    case NL_SIGN_ALG_HMAC_MD5:
161        cksumlen = NL_AUTH_SIGNATURE_LENGTH;
162        break;
163    case NL_SIGN_ALG_SHA256:
164        cksumlen = NL_AUTH_SHA2_SIGNATURE_LENGTH;
165        break;
166    default:
167        return EINVAL;
168    }
169
170    if (sig->SealAlgorithm == NL_SEAL_ALG_NONE)
171        cksumlen -= 8; /* confounder is optional if no sealing */
172
173    if (len < cksumlen)
174        return KRB5_BAD_MSIZE;
175
176    /* Copy variable length checksum */
177    cksumlen = _netlogon_checksum_length(sig);
178    memcpy(sig->Checksum, p, cksumlen);
179    p += cksumlen;
180
181    /* Copy confounder in past checksum */
182    if (sig->SealAlgorithm != NL_SEAL_ALG_NONE)
183        memcpy(&sig->Checksum[cksumlen], p, 8);
184
185    return 0;
186}
187
188static void
189_netlogon_derive_rc4_hmac_key(uint8_t key[16],
190                              uint8_t *salt,
191                              size_t saltLength,
192                              EVP_CIPHER_CTX *rc4Key,
193                              int enc)
194{
195    uint8_t tmpData[CC_MD5_DIGEST_LENGTH];
196    uint8_t derivedKey[CC_MD5_DIGEST_LENGTH];
197
198    CCHmac(kCCHmacAlgMD5, key, 16, zeros, sizeof(zeros), tmpData);
199    CCHmac(kCCHmacAlgMD5, tmpData, sizeof(tmpData), salt, saltLength, derivedKey);
200
201    EVP_CipherInit_ex(rc4Key, EVP_rc4(), NULL, derivedKey, NULL, enc);
202
203    memset(tmpData, 0, sizeof(tmpData));
204    memset(derivedKey, 0, sizeof(derivedKey));
205}
206
207static void
208_netlogon_derive_rc4_seal_key(gssnetlogon_ctx ctx,
209                              NL_AUTH_SIGNATURE *sig,
210                              EVP_CIPHER_CTX *sealkey,
211                              int enc)
212{
213    uint8_t xorKey[16];
214    size_t i;
215
216    for (i = 0; i < sizeof(xorKey); i++) {
217        xorKey[i] = ctx->SessionKey[i] ^ 0xF0;
218    }
219
220    _netlogon_derive_rc4_hmac_key(xorKey,
221        sig->SequenceNumber, sizeof(sig->SequenceNumber), sealkey, enc);
222
223    memset(xorKey, 0, sizeof(xorKey));
224}
225
226static void
227_netlogon_derive_rc4_seq_key(gssnetlogon_ctx ctx,
228                             NL_AUTH_SIGNATURE *sig,
229                             EVP_CIPHER_CTX *seqkey,
230                             int enc)
231{
232    _netlogon_derive_rc4_hmac_key(ctx->SessionKey,
233        sig->Checksum, sizeof(sig->Checksum), seqkey, enc);
234}
235
236static void
237_netlogon_derive_aes_seal_key(gssnetlogon_ctx ctx,
238                              NL_AUTH_SIGNATURE *sig,
239                              EVP_CIPHER_CTX *sealkey,
240                              int enc)
241{
242    uint8_t encryptionKey[16];
243    uint8_t ivec[16];
244    size_t i;
245
246    for (i = 0; i < sizeof(encryptionKey); i++) {
247        encryptionKey[i] = ctx->SessionKey[i] ^ 0xF0;
248    }
249
250    memcpy(&ivec[0], sig->SequenceNumber, 8);
251    memcpy(&ivec[8], sig->SequenceNumber, 8);
252
253    EVP_CipherInit_ex(sealkey, EVP_aes_128_cfb8(),
254                      NULL, encryptionKey, ivec, enc);
255
256    memset(encryptionKey, 0, sizeof(encryptionKey));
257}
258
259static void
260_netlogon_derive_aes_seq_key(gssnetlogon_ctx ctx,
261                             NL_AUTH_SIGNATURE *sig,
262                             EVP_CIPHER_CTX *seqkey,
263                             int enc)
264{
265    uint8_t ivec[16];
266
267    memcpy(&ivec[0], sig->Checksum, 8);
268    memcpy(&ivec[8], sig->Checksum, 8);
269
270    EVP_CipherInit_ex(seqkey, EVP_aes_128_cfb8(),
271                      NULL, ctx->SessionKey, ivec, enc);
272}
273
274static void
275_netlogon_seal(gssnetlogon_ctx ctx,
276               NL_AUTH_SIGNATURE *sig,
277               gss_iov_buffer_desc *iov,
278               int iov_count,
279               int enc)
280{
281    EVP_CIPHER_CTX sealkey;
282    int i;
283    uint8_t *confounder = _netlogon_confounder(sig);
284
285    EVP_CIPHER_CTX_init(&sealkey);
286
287    if (sig->SealAlgorithm == NL_SEAL_ALG_AES128)
288        _netlogon_derive_aes_seal_key(ctx, sig, &sealkey, enc);
289    else
290        _netlogon_derive_rc4_seal_key(ctx, sig, &sealkey, enc);
291
292    EVP_Cipher(&sealkey, confounder, confounder, 8);
293
294    /*
295     * For RC4, Windows resets the cipherstate after encrypting
296     * the confounder, thus defeating the purpose of the confounder
297     */
298    if (sig->SealAlgorithm == NL_SEAL_ALG_RC4) {
299        EVP_CipherFinal_ex(&sealkey, NULL, &i);
300        _netlogon_derive_rc4_seal_key(ctx, sig, &sealkey, enc);
301    }
302
303    for (i = 0; i < iov_count; i++) {
304        gss_iov_buffer_t iovp = &iov[i];
305
306        switch (GSS_IOV_BUFFER_TYPE(iovp->type)) {
307        case GSS_IOV_BUFFER_TYPE_DATA:
308        case GSS_IOV_BUFFER_TYPE_PADDING:
309            EVP_Cipher(&sealkey, iovp->buffer.value, iovp->buffer.value,
310                       iovp->buffer.length);
311            break;
312        default:
313            break;
314        }
315    }
316
317    EVP_CipherFinal_ex(&sealkey, NULL, &i);
318    EVP_CIPHER_CTX_cleanup(&sealkey);
319}
320
321static void
322_netlogon_seq(gssnetlogon_ctx ctx,
323              NL_AUTH_SIGNATURE *sig,
324              int enc)
325{
326    EVP_CIPHER_CTX seqkey;
327
328    EVP_CIPHER_CTX_init(&seqkey);
329
330    if (sig->SignatureAlgorithm == NL_SIGN_ALG_SHA256)
331        _netlogon_derive_aes_seq_key(ctx, sig, &seqkey, enc);
332    else
333        _netlogon_derive_rc4_seq_key(ctx, sig, &seqkey, enc);
334
335    EVP_Cipher(&seqkey, sig->SequenceNumber, sig->SequenceNumber, 8);
336
337    EVP_CIPHER_CTX_cleanup(&seqkey);
338}
339
340static void
341_netlogon_digest_md5(gssnetlogon_ctx ctx,
342                     NL_AUTH_SIGNATURE *sig,
343                     gss_iov_buffer_desc *iov,
344                     int iov_count,
345                     uint8_t *md)
346{
347    CCDigestRef md5;
348    uint8_t header[NL_AUTH_SIGNATURE_HEADER_LENGTH];
349    uint8_t digest[CC_MD5_DIGEST_LENGTH];
350    int i;
351
352    _netlogon_encode_NL_AUTH_SIGNATURE(sig, header, sizeof(header));
353
354    md5 = CCDigestCreate(kCCDigestMD5);
355    CCDigestUpdate(md5, zeros, sizeof(zeros));
356    CCDigestUpdate(md5, header, sizeof(header));
357
358    if (sig->SealAlgorithm != NL_SEAL_ALG_NONE) {
359        CCDigestUpdate(md5, sig->Confounder, sizeof(sig->Confounder));
360    }
361
362    for (i = 0; i < iov_count; i++) {
363        gss_iov_buffer_t iovp = &iov[i];
364
365        switch (GSS_IOV_BUFFER_TYPE(iovp->type)) {
366        case GSS_IOV_BUFFER_TYPE_DATA:
367        case GSS_IOV_BUFFER_TYPE_PADDING:
368        case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
369            CCDigestUpdate(md5, iovp->buffer.value, iovp->buffer.length);
370            break;
371        default:
372            break;
373        }
374    }
375
376    CCDigestFinal(md5, digest);
377    CCDigestDestroy(md5);
378
379    CCHmac(kCCHmacAlgMD5, ctx->SessionKey, sizeof(ctx->SessionKey), digest, sizeof(digest), digest);
380    memcpy(md, digest, 8);
381}
382
383static void
384_netlogon_digest_sha256(gssnetlogon_ctx ctx,
385                        NL_AUTH_SIGNATURE *sig,
386                        gss_iov_buffer_desc *iov,
387                        int iov_count,
388                        uint8_t *md)
389{
390    CCHmacContext hmac;
391    uint8_t header[NL_AUTH_SIGNATURE_HEADER_LENGTH];
392    uint8_t digest[CC_SHA256_DIGEST_LENGTH];
393    int i;
394
395    /* Encode first 8 bytes of signature into header */
396    _netlogon_encode_NL_AUTH_SIGNATURE(sig, header, sizeof(header));
397
398    CCHmacInit(&hmac, kCCHmacAlgSHA256, ctx->SessionKey, sizeof(ctx->SessionKey));
399    CCHmacUpdate(&hmac, header, sizeof(header));
400
401    if (sig->SealAlgorithm != NL_SEAL_ALG_NONE) {
402        /*
403         * If the checksum length bug is ever fixed, then be sure to
404         * update this code to point to &sig->Checksum[32] as that is
405         * where the confounder is supposed to be.
406         */
407        CCHmacUpdate(&hmac, sig->Confounder, 8);
408    }
409
410    for (i = 0; i < iov_count; i++) {
411        gss_iov_buffer_t iovp = &iov[i];
412
413        switch (GSS_IOV_BUFFER_TYPE(iovp->type)) {
414        case GSS_IOV_BUFFER_TYPE_DATA:
415        case GSS_IOV_BUFFER_TYPE_PADDING:
416        case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
417            CCHmacUpdate(&hmac, iovp->buffer.value, iovp->buffer.length);
418            break;
419        default:
420            break;
421        }
422    }
423
424    CCHmacFinal(&hmac, digest);
425    memset(&hmac, 0, sizeof(hmac));
426    memcpy(md, digest, 8);
427}
428
429static void
430_netlogon_digest(gssnetlogon_ctx ctx,
431                 NL_AUTH_SIGNATURE *sig,
432                 gss_iov_buffer_desc *iov,
433                 int iov_count,
434                 uint8_t *md)
435{
436    if (sig->SignatureAlgorithm == NL_SIGN_ALG_SHA256)
437        _netlogon_digest_sha256(ctx, sig, iov, iov_count, md);
438    else
439        _netlogon_digest_md5(ctx, sig, iov, iov_count, md);
440}
441
442OM_uint32
443_netlogon_wrap_iov(OM_uint32 * minor_status,
444                   gss_ctx_id_t  context_handle,
445                   int conf_req_flag,
446                   gss_qop_t qop_req,
447                   int *conf_state,
448                   gss_iov_buffer_desc *iov,
449                   int iov_count)
450{
451    OM_uint32 ret;
452    gss_iov_buffer_t header;
453    NL_AUTH_SIGNATURE_U sigbuf = { { 0 } };
454    NL_AUTH_SIGNATURE *sig = NL_AUTH_SIGNATURE_P(&sigbuf);
455    gssnetlogon_ctx ctx = (gssnetlogon_ctx)context_handle;
456    size_t size;
457
458    if (ctx->State != NL_AUTH_ESTABLISHED) {
459        *minor_status = EINVAL;
460        return GSS_S_FAILURE;
461    }
462
463    header = _gss_mg_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
464    if (header == NULL) {
465        *minor_status = EINVAL;
466        return GSS_S_FAILURE;
467    }
468
469    size = _netlogon_signature_length(ctx->SignatureAlgorithm, conf_req_flag);
470
471    if (GSS_IOV_BUFFER_FLAGS(header->type) & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
472        ret = _gss_mg_allocate_buffer(minor_status, header, size);
473        if (GSS_ERROR(ret))
474            return ret;
475    } else if (header->buffer.length < size) {
476        *minor_status = KRB5_BAD_MSIZE;
477        return GSS_S_FAILURE;
478    } else {
479        header->buffer.length = size;
480    }
481
482    memset(header->buffer.value, 0, header->buffer.length);
483
484    sig->SignatureAlgorithm = ctx->SignatureAlgorithm;
485    sig->SealAlgorithm = conf_req_flag ? ctx->SealAlgorithm : NL_SEAL_ALG_NONE;
486
487    if (conf_req_flag)
488        krb5_generate_random_block(_netlogon_confounder(sig), 8);
489
490    sig->Pad = 0xFFFF;              /* [MS-NRPC] 3.3.4.2.1.3 */
491    sig->Flags = 0;                 /* [MS-NRPC] 3.3.4.2.1.4 */
492    HEIMDAL_MUTEX_lock(&ctx->Mutex);
493    _netlogon_encode_sequence_number(ctx->SequenceNumber, sig->SequenceNumber,
494                                     ctx->LocallyInitiated);
495    ctx->SequenceNumber++;
496    HEIMDAL_MUTEX_unlock(&ctx->Mutex);
497
498    /* [MS-NRPC] 3.3.4.2.1.7: sign header, optional confounder and data  */
499    _netlogon_digest(ctx, sig, iov, iov_count, sig->Checksum);
500
501    /* [MS-NRPC] 3.3.4.2.1.8: optionally encrypt confounder and data */
502    if (conf_req_flag)
503        _netlogon_seal(ctx, sig, iov, iov_count, 1);
504
505    /* [MS-NRPC] 3.3.4.2.1.9: encrypt sequence number */
506    _netlogon_seq(ctx, sig, 1);
507
508    _netlogon_encode_NL_AUTH_SIGNATURE(sig, header->buffer.value,
509                                       header->buffer.length);
510
511    if (conf_state != NULL)
512        *conf_state = conf_req_flag;
513
514    *minor_status = 0;
515    return GSS_S_COMPLETE;
516}
517
518OM_uint32
519_netlogon_unwrap_iov(OM_uint32 *minor_status,
520                     gss_ctx_id_t context_handle,
521                     int *conf_state,
522                     gss_qop_t *qop_state,
523                     gss_iov_buffer_desc *iov,
524                     int iov_count)
525{
526    OM_uint32 ret;
527    gss_iov_buffer_t header;
528    NL_AUTH_SIGNATURE_U sigbuf;
529    NL_AUTH_SIGNATURE *sig = NL_AUTH_SIGNATURE_P(&sigbuf);
530    gssnetlogon_ctx ctx = (gssnetlogon_ctx)context_handle;
531    uint8_t checksum[CC_SHA256_DIGEST_LENGTH];
532    uint64_t SequenceNumber;
533
534    if (ctx->State != NL_AUTH_ESTABLISHED) {
535        *minor_status = EINVAL;
536        return GSS_S_FAILURE;
537    }
538
539    header = _gss_mg_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
540    if (header == NULL) {
541        *minor_status = EINVAL;
542        return GSS_S_FAILURE;
543    }
544
545    ret = _netlogon_decode_NL_AUTH_SIGNATURE(header->buffer.value,
546                                             header->buffer.length,
547                                             sig);
548    if (ret != 0) {
549        *minor_status = ret;
550        return GSS_S_DEFECTIVE_TOKEN;
551    }
552
553    /* [MS-NRPC] 3.3.4.2.2.1: verify signature algorithm selection */
554    if (sig->SignatureAlgorithm != ctx->SignatureAlgorithm)
555        return GSS_S_BAD_SIG;
556
557    /* [MS-NRPC] 3.3.4.2.2.2: verify encryption algorithm selection */
558    if (sig->SealAlgorithm != NL_SEAL_ALG_NONE &&
559        sig->SealAlgorithm != ctx->SealAlgorithm)
560        return GSS_S_DEFECTIVE_TOKEN;
561
562    /* [MS-NRPC] 3.3.4.2.2.3: verify Pad bytes */
563    if (sig->Pad != 0xFFFF)
564        return GSS_S_DEFECTIVE_TOKEN;
565
566    /* [MS-NRPC] 3.3.4.2.2.5: decrypt sequence number */
567    _netlogon_seq(ctx, sig, 0);
568
569    /* [MS-NRPC] 3.3.4.2.2.6: decode sequence number */
570    if (_netlogon_decode_sequence_number(sig->SequenceNumber, &SequenceNumber,
571                                         !ctx->LocallyInitiated) != 0)
572        return GSS_S_UNSEQ_TOKEN;
573
574    /* [MS-NRPC] 3.3.4.2.2.9: decrypt confounder and data */
575    if (sig->SealAlgorithm != NL_SEAL_ALG_NONE)
576        _netlogon_seal(ctx, sig, iov, iov_count, 0);
577
578    /* [MS-NRPC] 3.3.4.2.2.10: verify signature */
579    _netlogon_digest(ctx, sig, iov, iov_count, checksum);
580    if (memcmp(sig->Checksum, checksum, _netlogon_checksum_length(sig)) != 0)
581        return GSS_S_BAD_SIG;
582
583    HEIMDAL_MUTEX_lock(&ctx->Mutex);
584    if (SequenceNumber != ctx->SequenceNumber) {
585        /* [MS-NRPC] 3.3.4.2.2.7: check sequence number */
586        ret = GSS_S_UNSEQ_TOKEN;
587    } else {
588        /* [MS-NRPC] 3.3.4.2.2.8: increment sequence number */
589        ctx->SequenceNumber++;
590        ret = GSS_S_COMPLETE;
591    }
592    HEIMDAL_MUTEX_unlock(&ctx->Mutex);
593
594    if (conf_state != NULL)
595        *conf_state = (sig->SealAlgorithm != NL_SEAL_ALG_NONE);
596    if (qop_state != NULL)
597        *qop_state = GSS_C_QOP_DEFAULT;
598
599    *minor_status = 0;
600    return ret;
601}
602
603OM_uint32
604_netlogon_wrap_iov_length(OM_uint32 * minor_status,
605        	          gss_ctx_id_t context_handle,
606        	          int conf_req_flag,
607        	          gss_qop_t qop_req,
608        	          int *conf_state,
609        	          gss_iov_buffer_desc *iov,
610        	          int iov_count)
611{
612    gss_iov_buffer_t iovp;
613    gssnetlogon_ctx ctx = (gssnetlogon_ctx)context_handle;
614    size_t len;
615
616    iovp = _gss_mg_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
617    if (iovp == NULL) {
618        *minor_status = EINVAL;
619        return GSS_S_FAILURE;
620    }
621
622    len = NL_AUTH_SIGNATURE_COMMON_LENGTH;
623    if (ctx->SignatureAlgorithm == NL_SIGN_ALG_SHA256)
624        len += 32;  /* SHA2 checksum size */
625    else
626        len += 8;   /* HMAC checksum size */
627    if (conf_req_flag)
628        len += 8;   /* counfounder */
629
630    iovp->buffer.length = len;
631
632    iovp = _gss_mg_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
633    if (iovp != NULL)
634        iovp->buffer.length = 0;
635
636    iovp = _gss_mg_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
637    if (iovp != NULL)
638        iovp->buffer.length = 0;
639
640    if (conf_state != NULL)
641        *conf_state = conf_req_flag;
642
643    *minor_status = 0;
644    return GSS_S_COMPLETE;
645}
646
647OM_uint32 _netlogon_get_mic
648           (OM_uint32 * minor_status,
649            const gss_ctx_id_t context_handle,
650            gss_qop_t qop_req,
651            const gss_buffer_t message_buffer,
652            gss_buffer_t message_token
653           )
654{
655    gss_iov_buffer_desc iov[2];
656    OM_uint32 ret;
657
658    iov[0].type = GSS_IOV_BUFFER_TYPE_DATA;
659    iov[0].buffer = *message_buffer;
660    iov[1].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_FLAG_ALLOCATE;
661    iov[1].buffer.length = 0;
662    iov[1].buffer.value = NULL;
663
664    ret = _netlogon_wrap_iov(minor_status, context_handle, 0,
665                             qop_req, NULL, iov, 2);
666    if (ret == GSS_S_COMPLETE)
667        *message_token = iov[1].buffer;
668
669    return ret;
670}
671
672OM_uint32
673_netlogon_verify_mic
674           (OM_uint32 * minor_status,
675            const gss_ctx_id_t context_handle,
676            const gss_buffer_t message_buffer,
677            const gss_buffer_t token_buffer,
678            gss_qop_t * qop_state
679            )
680{
681    gss_iov_buffer_desc iov[2];
682
683    iov[0].type = GSS_IOV_BUFFER_TYPE_DATA;
684    iov[0].buffer = *message_buffer;
685    iov[1].type = GSS_IOV_BUFFER_TYPE_HEADER;
686    iov[1].buffer = *token_buffer;
687
688    return _netlogon_unwrap_iov(minor_status, context_handle,
689                                NULL, qop_state, iov, 2);
690}
691
692OM_uint32
693_netlogon_wrap_size_limit (
694            OM_uint32 * minor_status,
695            const gss_ctx_id_t context_handle,
696            int conf_req_flag,
697            gss_qop_t qop_req,
698            OM_uint32 req_output_size,
699            OM_uint32 *max_input_size
700           )
701{
702    gss_iov_buffer_desc iov[1];
703    OM_uint32 ret;
704
705    iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
706    iov[0].buffer.length = 0;
707
708    ret = _netlogon_wrap_iov_length(minor_status, context_handle,
709                                    conf_req_flag, qop_req, NULL,
710                                    iov, sizeof(iov)/sizeof(iov[0]));
711    if (GSS_ERROR(ret))
712        return ret;
713
714    if (req_output_size < iov[0].buffer.length)
715        *max_input_size = 0;
716    else
717        *max_input_size = (OM_uint32)(req_output_size - iov[0].buffer.length);
718
719    return GSS_S_COMPLETE;
720}
721
722