libkafs: derivation from non-DES key (rxkad-kdf)
[heimdal.git] / lib / gssapi / netlogon / crypto.c
blob0fc8f019d645d36fec5ce84629d2a30b5bd1fd51
1 /*
2 * Copyright (c) 2010 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Portions Copyright (c) 2010 Apple Inc. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
36 #include "netlogon.h"
38 static uint8_t zeros[4];
40 static void
41 _netlogon_encode_sequence_number(uint64_t SequenceNumber, uint8_t *p,
42 int initiatorFlag)
44 uint32_t LowPart, HighPart;
46 LowPart = (SequenceNumber >> 0 ) & 0xFFFFFFFF;
47 HighPart = (SequenceNumber >> 32) & 0xFFFFFFFF;
49 _gss_mg_encode_be_uint32(LowPart, &p[0]);
50 _gss_mg_encode_be_uint32(HighPart, &p[4]);
52 if (initiatorFlag)
53 p[4] |= 0x80;
56 static int
57 _netlogon_decode_sequence_number(void *ptr, uint64_t *n,
58 int initiatorFlag)
60 uint8_t *p = ptr;
61 uint32_t LowPart, HighPart;
62 int gotInitiatorFlag;
64 gotInitiatorFlag = (p[4] & 0x80) != 0;
65 if (gotInitiatorFlag != initiatorFlag)
66 return -1;
68 p[4] &= 0x7F; /* clear initiator bit */
70 _gss_mg_decode_be_uint32(&p[0], &LowPart);
71 _gss_mg_decode_be_uint32(&p[4], &HighPart);
73 *n = (LowPart << 0) | ((uint64_t)HighPart << 32);
75 return 0;
78 static inline size_t
79 _netlogon_checksum_length(NL_AUTH_SIGNATURE *sig)
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
89 static inline size_t
90 _netlogon_signature_length(uint16_t alg, int conf_req_flag)
92 return NL_AUTH_SIGNATURE_COMMON_LENGTH +
93 (alg == NL_SIGN_ALG_SHA256 ? 32 : 8) +
94 (conf_req_flag ? 8 : 0);
97 static inline uint8_t *
98 _netlogon_confounder(NL_AUTH_SIGNATURE *sig)
100 size_t cksumlen = _netlogon_checksum_length(sig);
102 return &sig->Checksum[cksumlen];
105 static int
106 _netlogon_encode_NL_AUTH_SIGNATURE(NL_AUTH_SIGNATURE *sig,
107 uint8_t *p, size_t len)
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;
118 if (len > NL_AUTH_SIGNATURE_HEADER_LENGTH) {
119 memcpy(p, sig->SequenceNumber, 8);
120 p += 8;
123 if (len > NL_AUTH_SIGNATURE_COMMON_LENGTH) {
124 size_t cksumlen = _netlogon_checksum_length(sig);
126 memcpy(p, sig->Checksum, cksumlen);
127 p += cksumlen;
129 /* Confounder, if present, is immediately after checksum */
130 if (sig->SealAlgorithm != NL_SEAL_ALG_NONE) {
131 memcpy(p, &sig->Checksum[cksumlen], 8);
135 return 0;
138 static int
139 _netlogon_decode_NL_AUTH_SIGNATURE(const uint8_t *ptr,
140 size_t len,
141 NL_AUTH_SIGNATURE *sig)
143 const uint8_t *p = ptr;
144 size_t cksumlen;
146 if (len < NL_AUTH_SIGNATURE_COMMON_LENGTH)
147 return KRB5_BAD_MSIZE;
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;
155 memcpy(sig->SequenceNumber, p, 8);
156 p += 8;
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 break;
171 if (sig->SealAlgorithm == NL_SEAL_ALG_NONE)
172 cksumlen -= 8; /* confounder is optional if no sealing */
174 if (len < cksumlen)
175 return KRB5_BAD_MSIZE;
177 /* Copy variable length checksum */
178 cksumlen = _netlogon_checksum_length(sig);
179 memcpy(sig->Checksum, p, cksumlen);
180 p += cksumlen;
182 /* Copy confounder in past checksum */
183 if (sig->SealAlgorithm != NL_SEAL_ALG_NONE)
184 memcpy(&sig->Checksum[cksumlen], p, 8);
186 return 0;
189 static void
190 _netlogon_derive_rc4_hmac_key(uint8_t key[16],
191 uint8_t *salt,
192 size_t saltLength,
193 EVP_CIPHER_CTX *rc4Key,
194 int enc)
196 uint8_t tmpData[MD5_DIGEST_LENGTH];
197 uint8_t derivedKey[MD5_DIGEST_LENGTH];
198 unsigned int len = MD5_DIGEST_LENGTH;
200 HMAC(EVP_md5(), key, 16, zeros, sizeof(zeros), tmpData, &len);
201 HMAC(EVP_md5(), tmpData, MD5_DIGEST_LENGTH,
202 salt, saltLength, derivedKey, &len);
204 assert(len == MD5_DIGEST_LENGTH);
206 EVP_CipherInit_ex(rc4Key, EVP_rc4(), NULL, derivedKey, NULL, enc);
208 memset(derivedKey, 0, sizeof(derivedKey));
211 static void
212 _netlogon_derive_rc4_seal_key(gssnetlogon_ctx ctx,
213 NL_AUTH_SIGNATURE *sig,
214 EVP_CIPHER_CTX *sealkey,
215 int enc)
217 uint8_t xorKey[16];
218 int i;
220 for (i = 0; i < sizeof(xorKey); i++) {
221 xorKey[i] = ctx->SessionKey[i] ^ 0xF0;
224 _netlogon_derive_rc4_hmac_key(xorKey,
225 sig->SequenceNumber, sizeof(sig->SequenceNumber), sealkey, enc);
227 memset(xorKey, 0, sizeof(xorKey));
230 static void
231 _netlogon_derive_rc4_seq_key(gssnetlogon_ctx ctx,
232 NL_AUTH_SIGNATURE *sig,
233 EVP_CIPHER_CTX *seqkey,
234 int enc)
236 _netlogon_derive_rc4_hmac_key(ctx->SessionKey,
237 sig->Checksum, sizeof(sig->Checksum), seqkey, enc);
240 static void
241 _netlogon_derive_aes_seal_key(gssnetlogon_ctx ctx,
242 NL_AUTH_SIGNATURE *sig,
243 EVP_CIPHER_CTX *sealkey,
244 int enc)
246 uint8_t encryptionKey[16];
247 uint8_t ivec[16];
248 int i;
250 for (i = 0; i < sizeof(encryptionKey); i++) {
251 encryptionKey[i] = ctx->SessionKey[i] ^ 0xF0;
254 memcpy(&ivec[0], sig->SequenceNumber, 8);
255 memcpy(&ivec[8], sig->SequenceNumber, 8);
257 EVP_CipherInit_ex(sealkey, EVP_aes_128_cfb8(),
258 NULL, encryptionKey, ivec, enc);
260 memset(encryptionKey, 0, sizeof(encryptionKey));
263 static void
264 _netlogon_derive_aes_seq_key(gssnetlogon_ctx ctx,
265 NL_AUTH_SIGNATURE *sig,
266 EVP_CIPHER_CTX *seqkey,
267 int enc)
269 uint8_t ivec[16];
271 memcpy(&ivec[0], sig->Checksum, 8);
272 memcpy(&ivec[8], sig->Checksum, 8);
274 EVP_CipherInit_ex(seqkey, EVP_aes_128_cfb8(),
275 NULL, ctx->SessionKey, ivec, enc);
278 static void
279 _netlogon_seal(gssnetlogon_ctx ctx,
280 NL_AUTH_SIGNATURE *sig,
281 gss_iov_buffer_desc *iov,
282 int iov_count,
283 int enc)
285 EVP_CIPHER_CTX sealkey;
286 int i;
287 uint8_t *confounder = _netlogon_confounder(sig);
289 EVP_CIPHER_CTX_init(&sealkey);
291 if (sig->SealAlgorithm == NL_SEAL_ALG_AES128)
292 _netlogon_derive_aes_seal_key(ctx, sig, &sealkey, enc);
293 else
294 _netlogon_derive_rc4_seal_key(ctx, sig, &sealkey, enc);
296 EVP_Cipher(&sealkey, confounder, confounder, 8);
299 * For RC4, Windows resets the cipherstate after encrypting
300 * the confounder, thus defeating the purpose of the confounder
302 if (sig->SealAlgorithm == NL_SEAL_ALG_RC4) {
303 EVP_CipherFinal_ex(&sealkey, NULL, &i);
304 _netlogon_derive_rc4_seal_key(ctx, sig, &sealkey, enc);
307 for (i = 0; i < iov_count; i++) {
308 gss_iov_buffer_t iovp = &iov[i];
310 switch (GSS_IOV_BUFFER_TYPE(iovp->type)) {
311 case GSS_IOV_BUFFER_TYPE_DATA:
312 case GSS_IOV_BUFFER_TYPE_PADDING:
313 EVP_Cipher(&sealkey, iovp->buffer.value, iovp->buffer.value,
314 iovp->buffer.length);
315 break;
316 default:
317 break;
321 EVP_CipherFinal_ex(&sealkey, NULL, &i);
322 EVP_CIPHER_CTX_cleanup(&sealkey);
325 static void
326 _netlogon_seq(gssnetlogon_ctx ctx,
327 NL_AUTH_SIGNATURE *sig,
328 int enc)
330 EVP_CIPHER_CTX seqkey;
332 EVP_CIPHER_CTX_init(&seqkey);
334 if (sig->SignatureAlgorithm == NL_SIGN_ALG_SHA256)
335 _netlogon_derive_aes_seq_key(ctx, sig, &seqkey, enc);
336 else
337 _netlogon_derive_rc4_seq_key(ctx, sig, &seqkey, enc);
339 EVP_Cipher(&seqkey, sig->SequenceNumber, sig->SequenceNumber, 8);
341 EVP_CIPHER_CTX_cleanup(&seqkey);
344 static void
345 _netlogon_digest_md5(gssnetlogon_ctx ctx,
346 NL_AUTH_SIGNATURE *sig,
347 gss_iov_buffer_desc *iov,
348 int iov_count,
349 uint8_t *md)
351 EVP_MD_CTX *md5;
352 uint8_t header[NL_AUTH_SIGNATURE_HEADER_LENGTH];
353 uint8_t digest[MD5_DIGEST_LENGTH];
354 unsigned int md_len = MD5_DIGEST_LENGTH;
355 int i;
357 _netlogon_encode_NL_AUTH_SIGNATURE(sig, header, sizeof(header));
359 md5 = EVP_MD_CTX_create();
360 EVP_DigestInit_ex(md5, EVP_md5(), NULL);
361 EVP_DigestUpdate(md5, zeros, sizeof(zeros));
362 EVP_DigestUpdate(md5, header, sizeof(header));
364 if (sig->SealAlgorithm != NL_SEAL_ALG_NONE) {
365 EVP_DigestUpdate(md5, sig->Confounder, sizeof(sig->Confounder));
368 for (i = 0; i < iov_count; i++) {
369 gss_iov_buffer_t iovp = &iov[i];
371 switch (GSS_IOV_BUFFER_TYPE(iovp->type)) {
372 case GSS_IOV_BUFFER_TYPE_DATA:
373 case GSS_IOV_BUFFER_TYPE_PADDING:
374 case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
375 EVP_DigestUpdate(md5, iovp->buffer.value, iovp->buffer.length);
376 break;
377 default:
378 break;
382 EVP_DigestFinal_ex(md5, digest, NULL);
383 EVP_MD_CTX_destroy(md5);
385 HMAC(EVP_md5(), ctx->SessionKey, sizeof(ctx->SessionKey),
386 digest, sizeof(digest), digest, &md_len);
387 memcpy(md, digest, 8);
390 static void
391 _netlogon_digest_sha256(gssnetlogon_ctx ctx,
392 NL_AUTH_SIGNATURE *sig,
393 gss_iov_buffer_desc *iov,
394 int iov_count,
395 uint8_t *md)
397 HMAC_CTX hmac;
398 uint8_t header[NL_AUTH_SIGNATURE_HEADER_LENGTH];
399 uint8_t digest[SHA256_DIGEST_LENGTH];
400 unsigned int md_len = SHA256_DIGEST_LENGTH;
401 int i;
403 /* Encode first 8 bytes of signature into header */
404 _netlogon_encode_NL_AUTH_SIGNATURE(sig, header, sizeof(header));
406 HMAC_CTX_init(&hmac);
407 HMAC_Init_ex(&hmac, ctx->SessionKey, sizeof(ctx->SessionKey),
408 EVP_sha256(), NULL);
409 HMAC_Update(&hmac, header, sizeof(header));
411 if (sig->SealAlgorithm != NL_SEAL_ALG_NONE) {
413 * If the checksum length bug is ever fixed, then be sure to
414 * update this code to point to &sig->Checksum[32] as that is
415 * where the confounder is supposed to be.
417 HMAC_Update(&hmac, sig->Confounder, 8);
420 for (i = 0; i < iov_count; i++) {
421 gss_iov_buffer_t iovp = &iov[i];
423 switch (GSS_IOV_BUFFER_TYPE(iovp->type)) {
424 case GSS_IOV_BUFFER_TYPE_DATA:
425 case GSS_IOV_BUFFER_TYPE_PADDING:
426 case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
427 HMAC_Update(&hmac, iovp->buffer.value, iovp->buffer.length);
428 break;
429 default:
430 break;
434 HMAC_Final(&hmac, digest, &md_len);
435 HMAC_CTX_cleanup(&hmac);
436 memcpy(md, digest, 8);
439 static void
440 _netlogon_digest(gssnetlogon_ctx ctx,
441 NL_AUTH_SIGNATURE *sig,
442 gss_iov_buffer_desc *iov,
443 int iov_count,
444 uint8_t *md)
446 if (sig->SignatureAlgorithm == NL_SIGN_ALG_SHA256)
447 _netlogon_digest_sha256(ctx, sig, iov, iov_count, md);
448 else
449 _netlogon_digest_md5(ctx, sig, iov, iov_count, md);
452 OM_uint32
453 _netlogon_wrap_iov(OM_uint32 * minor_status,
454 gss_ctx_id_t context_handle,
455 int conf_req_flag,
456 gss_qop_t qop_req,
457 int *conf_state,
458 gss_iov_buffer_desc *iov,
459 int iov_count)
461 OM_uint32 ret;
462 gss_iov_buffer_t header;
463 NL_AUTH_SIGNATURE_U sigbuf = { { 0 } };
464 NL_AUTH_SIGNATURE *sig = NL_AUTH_SIGNATURE_P(&sigbuf);
465 gssnetlogon_ctx ctx = (gssnetlogon_ctx)context_handle;
466 size_t size;
467 uint8_t *seqdata;
469 if (ctx->State != NL_AUTH_ESTABLISHED) {
470 *minor_status = EINVAL;
471 return GSS_S_FAILURE;
474 header = _gss_mg_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
475 if (header == NULL) {
476 *minor_status = EINVAL;
477 return GSS_S_FAILURE;
480 size = _netlogon_signature_length(ctx->SignatureAlgorithm, conf_req_flag);
482 if (GSS_IOV_BUFFER_FLAGS(header->type) & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
483 ret = _gss_mg_allocate_buffer(minor_status, header, size);
484 if (GSS_ERROR(ret))
485 return ret;
486 } else if (header->buffer.length < size) {
487 *minor_status = KRB5_BAD_MSIZE;
488 return GSS_S_FAILURE;
489 } else {
490 header->buffer.length = size;
493 memset(header->buffer.value, 0, header->buffer.length);
495 sig->SignatureAlgorithm = ctx->SignatureAlgorithm;
496 sig->SealAlgorithm = conf_req_flag ? ctx->SealAlgorithm : NL_SEAL_ALG_NONE;
498 if (conf_req_flag)
499 krb5_generate_random_block(_netlogon_confounder(sig), 8);
501 sig->Pad = 0xFFFF; /* [MS-NRPC] 3.3.4.2.1.3 */
502 sig->Flags = 0; /* [MS-NRPC] 3.3.4.2.1.4 */
503 HEIMDAL_MUTEX_lock(&ctx->Mutex);
504 _netlogon_encode_sequence_number(ctx->SequenceNumber, sig->SequenceNumber,
505 ctx->LocallyInitiated);
506 ctx->SequenceNumber++;
507 HEIMDAL_MUTEX_unlock(&ctx->Mutex);
509 /* [MS-NRPC] 3.3.4.2.1.7: sign header, optional confounder and data */
510 _netlogon_digest(ctx, sig, iov, iov_count, sig->Checksum);
512 /* [MS-NRPC] 3.3.4.2.1.8: optionally encrypt confounder and data */
513 if (conf_req_flag)
514 _netlogon_seal(ctx, sig, iov, iov_count, 1);
516 /* [MS-NRPC] 3.3.4.2.1.9: encrypt sequence number */
517 _netlogon_seq(ctx, sig, 1);
519 _netlogon_encode_NL_AUTH_SIGNATURE(sig, header->buffer.value,
520 header->buffer.length);
522 if (conf_state != NULL)
523 *conf_state = conf_req_flag;
525 *minor_status = 0;
526 return GSS_S_COMPLETE;
529 OM_uint32
530 _netlogon_unwrap_iov(OM_uint32 *minor_status,
531 gss_ctx_id_t context_handle,
532 int *conf_state,
533 gss_qop_t *qop_state,
534 gss_iov_buffer_desc *iov,
535 int iov_count)
537 OM_uint32 ret;
538 gss_iov_buffer_t header;
539 NL_AUTH_SIGNATURE_U sigbuf;
540 NL_AUTH_SIGNATURE *sig = NL_AUTH_SIGNATURE_P(&sigbuf);
541 gssnetlogon_ctx ctx = (gssnetlogon_ctx)context_handle;
542 uint8_t checksum[SHA256_DIGEST_LENGTH];
543 uint64_t SequenceNumber;
545 if (ctx->State != NL_AUTH_ESTABLISHED) {
546 *minor_status = EINVAL;
547 return GSS_S_FAILURE;
550 header = _gss_mg_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
551 if (header == NULL) {
552 *minor_status = EINVAL;
553 return GSS_S_FAILURE;
556 ret = _netlogon_decode_NL_AUTH_SIGNATURE(header->buffer.value,
557 header->buffer.length,
558 sig);
559 if (ret != 0) {
560 *minor_status = ret;
561 return GSS_S_DEFECTIVE_TOKEN;
564 /* [MS-NRPC] 3.3.4.2.2.1: verify signature algorithm selection */
565 if (sig->SignatureAlgorithm != ctx->SignatureAlgorithm)
566 return GSS_S_BAD_SIG;
568 /* [MS-NRPC] 3.3.4.2.2.2: verify encryption algorithm selection */
569 if (sig->SealAlgorithm != NL_SEAL_ALG_NONE &&
570 sig->SealAlgorithm != ctx->SealAlgorithm)
571 return GSS_S_DEFECTIVE_TOKEN;
573 /* [MS-NRPC] 3.3.4.2.2.3: verify Pad bytes */
574 if (sig->Pad != 0xFFFF)
575 return GSS_S_DEFECTIVE_TOKEN;
577 /* [MS-NRPC] 3.3.4.2.2.5: decrypt sequence number */
578 _netlogon_seq(ctx, sig, 0);
580 /* [MS-NRPC] 3.3.4.2.2.6: decode sequence number */
581 if (_netlogon_decode_sequence_number(sig->SequenceNumber, &SequenceNumber,
582 !ctx->LocallyInitiated) != 0)
583 return GSS_S_UNSEQ_TOKEN;
585 /* [MS-NRPC] 3.3.4.2.2.9: decrypt confounder and data */
586 if (sig->SealAlgorithm != NL_SEAL_ALG_NONE)
587 _netlogon_seal(ctx, sig, iov, iov_count, 0);
589 /* [MS-NRPC] 3.3.4.2.2.10: verify signature */
590 _netlogon_digest(ctx, sig, iov, iov_count, checksum);
591 if (memcmp(sig->Checksum, checksum, _netlogon_checksum_length(sig)) != 0)
592 return GSS_S_BAD_SIG;
594 HEIMDAL_MUTEX_lock(&ctx->Mutex);
595 if (SequenceNumber != ctx->SequenceNumber) {
596 /* [MS-NRPC] 3.3.4.2.2.7: check sequence number */
597 ret = GSS_S_UNSEQ_TOKEN;
598 } else {
599 /* [MS-NRPC] 3.3.4.2.2.8: increment sequence number */
600 ctx->SequenceNumber++;
601 ret = GSS_S_COMPLETE;
603 HEIMDAL_MUTEX_unlock(&ctx->Mutex);
605 if (conf_state != NULL)
606 *conf_state = (sig->SealAlgorithm != NL_SEAL_ALG_NONE);
607 if (qop_state != NULL)
608 *qop_state = GSS_C_QOP_DEFAULT;
610 *minor_status = 0;
611 return ret;
614 OM_uint32
615 _netlogon_wrap_iov_length(OM_uint32 * minor_status,
616 gss_ctx_id_t context_handle,
617 int conf_req_flag,
618 gss_qop_t qop_req,
619 int *conf_state,
620 gss_iov_buffer_desc *iov,
621 int iov_count)
623 OM_uint32 ret;
624 gss_iov_buffer_t iovp;
625 gssnetlogon_ctx ctx = (gssnetlogon_ctx)context_handle;
626 size_t len;
628 iovp = _gss_mg_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
629 if (iovp == NULL) {
630 *minor_status = EINVAL;
631 return GSS_S_FAILURE;
634 len = NL_AUTH_SIGNATURE_COMMON_LENGTH;
635 if (ctx->SignatureAlgorithm == NL_SIGN_ALG_SHA256)
636 len += 32; /* SHA2 checksum size */
637 else
638 len += 8; /* HMAC checksum size */
639 if (conf_req_flag)
640 len += 8; /* counfounder */
642 iovp->buffer.length = len;
644 iovp = _gss_mg_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
645 if (iovp != NULL)
646 iovp->buffer.length = 0;
648 iovp = _gss_mg_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
649 if (iovp != NULL)
650 iovp->buffer.length = 0;
652 if (conf_state != NULL)
653 *conf_state = conf_req_flag;
655 *minor_status = 0;
656 return GSS_S_COMPLETE;
659 OM_uint32 _netlogon_get_mic
660 (OM_uint32 * minor_status,
661 gss_const_ctx_id_t context_handle,
662 gss_qop_t qop_req,
663 const gss_buffer_t message_buffer,
664 gss_buffer_t message_token
667 gss_iov_buffer_desc iov[2];
668 OM_uint32 ret;
670 iov[0].type = GSS_IOV_BUFFER_TYPE_DATA;
671 iov[0].buffer = *message_buffer;
672 iov[1].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_FLAG_ALLOCATE;
673 iov[1].buffer.length = 0;
674 iov[1].buffer.value = NULL;
676 ret = _netlogon_wrap_iov(minor_status, context_handle, 0,
677 qop_req, NULL, iov, 2);
678 if (ret == GSS_S_COMPLETE)
679 *message_token = iov[1].buffer;
681 return ret;
684 OM_uint32
685 _netlogon_verify_mic
686 (OM_uint32 * minor_status,
687 gss_const_ctx_id_t context_handle,
688 const gss_buffer_t message_buffer,
689 const gss_buffer_t token_buffer,
690 gss_qop_t * qop_state
693 gss_iov_buffer_desc iov[2];
695 iov[0].type = GSS_IOV_BUFFER_TYPE_DATA;
696 iov[0].buffer = *message_buffer;
697 iov[1].type = GSS_IOV_BUFFER_TYPE_HEADER;
698 iov[1].buffer = *token_buffer;
700 return _netlogon_unwrap_iov(minor_status, context_handle,
701 NULL, qop_state, iov, 2);
704 OM_uint32
705 _netlogon_wrap_size_limit (
706 OM_uint32 * minor_status,
707 gss_const_ctx_id_t context_handle,
708 int conf_req_flag,
709 gss_qop_t qop_req,
710 OM_uint32 req_output_size,
711 OM_uint32 *max_input_size
714 gss_iov_buffer_desc iov[1];
715 OM_uint32 ret;
717 iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
718 iov[0].buffer.length = 0;
720 ret = _netlogon_wrap_iov_length(minor_status, context_handle,
721 conf_req_flag, qop_req, NULL,
722 iov, sizeof(iov)/sizeof(iov[0]));
723 if (GSS_ERROR(ret))
724 return ret;
726 if (req_output_size < iov[0].buffer.length)
727 *max_input_size = 0;
728 else
729 *max_input_size = req_output_size - iov[0].buffer.length;
731 return GSS_S_COMPLETE;