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