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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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