Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1649 lines
45 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. cnpmisc.c
  5. Abstract:
  6. Miscellaneous routines for the Cluster Network Protocol.
  7. Author:
  8. Mike Massa (mikemas) January 24, 1997
  9. Revision History:
  10. Who When What
  11. -------- -------- ----------------------------------------------
  12. mikemas 01-24-97 created
  13. Notes:
  14. --*/
  15. #include "precomp.h"
  16. #pragma hdrstop
  17. #include "cnpmisc.tmh"
  18. #include <tdiinfo.h>
  19. #include <tcpinfo.h>
  20. #include <fipsapi.h>
  21. #include <sspi.h>
  22. //
  23. // Salt generation
  24. //
  25. ULONGLONG CnpSaltBase = 0;
  26. #define CNP_SALTBASE_MULTIPLIER 31
  27. //
  28. // Local function prototypes
  29. //
  30. NTSTATUS
  31. CnpRestartDeviceControl (
  32. IN PDEVICE_OBJECT DeviceObject,
  33. IN PIRP Irp,
  34. IN PVOID Context
  35. );
  36. #ifdef ALLOC_PRAGMA
  37. //
  38. // All of this code is pageable.
  39. //
  40. #pragma alloc_text(PAGE, CnpTdiSetEventHandler)
  41. #pragma alloc_text(PAGE, CnpIssueDeviceControl)
  42. #pragma alloc_text(PAGE, CnpOpenDevice)
  43. #pragma alloc_text(PAGE, CnpZwDeviceControl)
  44. #pragma alloc_text(PAGE, CnpSetTcpInfoEx)
  45. #pragma alloc_text(PAGE, CnpInitializeSaltGenerator)
  46. #endif // ALLOC_PRAGMA
  47. NTSTATUS
  48. CnpRestartDeviceControl (
  49. IN PDEVICE_OBJECT DeviceObject,
  50. IN PIRP Irp,
  51. IN PVOID Context
  52. )
  53. {
  54. PBOOLEAN reuseIrp = (PBOOLEAN) Context;
  55. //
  56. // If there was an MDL in the IRP, free it and reset the pointer to
  57. // NULL. The IO system can't handle a nonpaged pool MDL being freed
  58. // in an IRP, which is why we do it here.
  59. //
  60. if ( Irp->MdlAddress != NULL ) {
  61. IoFreeMdl( Irp->MdlAddress );
  62. Irp->MdlAddress = NULL;
  63. }
  64. //
  65. // Mark the IRP pending, if necessary.
  66. //
  67. if (Irp->PendingReturned) {
  68. IoMarkIrpPending(Irp);
  69. }
  70. //
  71. // If we are reusing a client IRP, tell the I/O manager not to
  72. // halt I/O completion processing immediately.
  73. //
  74. if (*reuseIrp) {
  75. if (Irp->UserIosb != NULL) {
  76. *(Irp->UserIosb) = Irp->IoStatus;
  77. }
  78. if (Irp->UserEvent != NULL) {
  79. KeSetEvent(Irp->UserEvent, IO_NO_INCREMENT, FALSE);
  80. }
  81. return STATUS_MORE_PROCESSING_REQUIRED;
  82. } else {
  83. return STATUS_SUCCESS;
  84. }
  85. } // CnpRestartDeviceControl
  86. NTSTATUS
  87. CnpIssueDeviceControl (
  88. IN PFILE_OBJECT FileObject,
  89. IN PDEVICE_OBJECT DeviceObject,
  90. IN PVOID IrpParameters,
  91. IN ULONG IrpParametersLength,
  92. IN PVOID MdlBuffer,
  93. IN ULONG MdlBufferLength,
  94. IN UCHAR MinorFunction,
  95. IN PIRP ClientIrp OPTIONAL
  96. )
  97. /*++
  98. Routine Description:
  99. Issues a device control request to a TDI provider and waits for the
  100. request to complete.
  101. Arguments:
  102. FileObject - a pointer to the file object corresponding to a TDI
  103. handle
  104. DeviceObject - a pointer to the device object corresponding to the
  105. FileObject.
  106. IrpParameters - information to write to the parameters section of the
  107. stack location of the IRP.
  108. IrpParametersLength - length of the parameter information. Cannot be
  109. greater than 16.
  110. MdlBuffer - if non-NULL, a buffer of nonpaged pool to be mapped
  111. into an MDL and placed in the MdlAddress field of the IRP.
  112. MdlBufferLength - the size of the buffer pointed to by MdlBuffer.
  113. MinorFunction - the minor function code for the request.
  114. ClientIrp - client IRP that may be reusable for this ioctl
  115. Return Value:
  116. NTSTATUS -- Indicates the status of the request.
  117. --*/
  118. {
  119. NTSTATUS status = STATUS_SUCCESS;
  120. PIRP irp;
  121. PIO_STACK_LOCATION irpSp;
  122. KEVENT event;
  123. IO_STATUS_BLOCK ioStatusBlock;
  124. PDEVICE_OBJECT deviceObject;
  125. PMDL mdl;
  126. KPROCESSOR_MODE clientRequestorMode;
  127. PKEVENT clientUserEvent;
  128. PIO_STATUS_BLOCK clientIosb;
  129. PMDL clientMdl;
  130. BOOLEAN reuseIrp = FALSE;
  131. PAGED_CODE( );
  132. //
  133. // Initialize the kernel event that will signal I/O completion.
  134. //
  135. KeInitializeEvent( &event, SynchronizationEvent, FALSE );
  136. //
  137. // If there is a ClientIrp available, check if it has sufficient
  138. // stack locations.
  139. //
  140. if (ClientIrp != NULL
  141. && CnpIsIrpStackSufficient(ClientIrp, DeviceObject)) {
  142. //
  143. // Reuse the client IRP rather than allocating a new one.
  144. //
  145. reuseIrp = TRUE;
  146. irp = ClientIrp;
  147. //
  148. // Save state from client IRP
  149. //
  150. clientRequestorMode = irp->RequestorMode;
  151. clientUserEvent = irp->UserEvent;
  152. clientIosb = irp->UserIosb;
  153. clientMdl = irp->MdlAddress;
  154. } else {
  155. //
  156. // Reference the passed in file object. This is necessary because
  157. // the IO completion routine dereferences it.
  158. //
  159. ObReferenceObject( FileObject );
  160. //
  161. // Set the file object event to a non-signaled state.
  162. //
  163. (VOID) KeResetEvent( &FileObject->Event );
  164. //
  165. // Attempt to allocate and initialize the I/O Request Packet (IRP)
  166. // for this operation.
  167. //
  168. irp = IoAllocateIrp( (DeviceObject)->StackSize, TRUE );
  169. if ( irp == NULL ) {
  170. ObDereferenceObject( FileObject );
  171. return STATUS_INSUFFICIENT_RESOURCES;
  172. }
  173. //
  174. // Fill in the service independent parameters in the IRP.
  175. //
  176. irp->Flags = (LONG)IRP_SYNCHRONOUS_API;
  177. irp->PendingReturned = FALSE;
  178. irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
  179. irp->AssociatedIrp.SystemBuffer = NULL;
  180. irp->UserBuffer = NULL;
  181. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  182. irp->Tail.Overlay.OriginalFileObject = FileObject;
  183. irp->Tail.Overlay.AuxiliaryBuffer = NULL;
  184. //
  185. // Queue the IRP to the thread.
  186. //
  187. IoEnqueueIrp( irp );
  188. }
  189. //
  190. // If an MDL buffer was specified, get an MDL, map the buffer,
  191. // and place the MDL pointer in the IRP.
  192. //
  193. if ( MdlBuffer != NULL ) {
  194. mdl = IoAllocateMdl(
  195. MdlBuffer,
  196. MdlBufferLength,
  197. FALSE,
  198. FALSE,
  199. irp
  200. );
  201. if ( mdl == NULL ) {
  202. if (!reuseIrp) {
  203. IoFreeIrp( irp );
  204. ObDereferenceObject( FileObject );
  205. } else {
  206. irp->MdlAddress = clientMdl;
  207. }
  208. return STATUS_INSUFFICIENT_RESOURCES;
  209. }
  210. MmBuildMdlForNonPagedPool( mdl );
  211. } else {
  212. irp->MdlAddress = NULL;
  213. }
  214. irp->RequestorMode = KernelMode;
  215. irp->UserIosb = &ioStatusBlock;
  216. irp->UserEvent = &event;
  217. //
  218. // Put the file object pointer in the stack location.
  219. //
  220. irpSp = IoGetNextIrpStackLocation( irp );
  221. irpSp->FileObject = FileObject;
  222. irpSp->DeviceObject = DeviceObject;
  223. //
  224. // Fill in the service-dependent parameters for the request.
  225. //
  226. CnAssert( IrpParametersLength <= sizeof(irpSp->Parameters) );
  227. RtlCopyMemory( &irpSp->Parameters, IrpParameters, IrpParametersLength );
  228. irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  229. irpSp->MinorFunction = MinorFunction;
  230. //
  231. // Set up a completion routine which we'll use to free the MDL
  232. // allocated previously.
  233. //
  234. IoSetCompletionRoutine(
  235. irp,
  236. CnpRestartDeviceControl,
  237. (PVOID) &reuseIrp,
  238. TRUE,
  239. TRUE,
  240. TRUE
  241. );
  242. status = IoCallDriver( DeviceObject, irp );
  243. //
  244. // If necessary, wait for the I/O to complete.
  245. //
  246. if ( status == STATUS_PENDING ) {
  247. KeWaitForSingleObject(
  248. (PVOID)&event,
  249. UserRequest,
  250. KernelMode,
  251. FALSE,
  252. NULL
  253. );
  254. }
  255. //
  256. // If the request was successfully queued, get the final I/O status.
  257. //
  258. if ( NT_SUCCESS(status) ) {
  259. status = ioStatusBlock.Status;
  260. }
  261. //
  262. // Before returning, restore the client IRP
  263. //
  264. if (reuseIrp) {
  265. irp->RequestorMode = clientRequestorMode;
  266. irp->UserIosb = clientIosb;
  267. irp->UserEvent = clientUserEvent;
  268. irp->MdlAddress = clientMdl;
  269. }
  270. return status;
  271. } // CnpIssueDeviceControl
  272. NTSTATUS
  273. CnpTdiSetEventHandler(
  274. IN PFILE_OBJECT FileObject,
  275. IN PDEVICE_OBJECT DeviceObject,
  276. IN ULONG EventType,
  277. IN PVOID EventHandler,
  278. IN PVOID EventContext,
  279. IN PIRP ClientIrp OPTIONAL
  280. )
  281. /*++
  282. Routine Description:
  283. Sets up a TDI indication handler on a connection or address object
  284. (depending on the file handle). This is done synchronously, which
  285. shouldn't usually be an issue since TDI providers can usually complete
  286. indication handler setups immediately.
  287. Arguments:
  288. FileObject - a pointer to the file object for an open connection or
  289. address object.
  290. DeviceObject - a pointer to the device object associated with the
  291. file object.
  292. EventType - the event for which the indication handler should be
  293. called.
  294. EventHandler - the routine to call when tghe specified event occurs.
  295. EventContext - context which is passed to the indication routine.
  296. ClientIrp - client IRP that may be passed to CnpIssueDeviceControl
  297. for reuse
  298. Return Value:
  299. NTSTATUS -- Indicates the status of the request.
  300. --*/
  301. {
  302. TDI_REQUEST_KERNEL_SET_EVENT parameters;
  303. NTSTATUS status;
  304. PAGED_CODE( );
  305. parameters.EventType = EventType;
  306. parameters.EventHandler = EventHandler;
  307. parameters.EventContext = EventContext;
  308. status = CnpIssueDeviceControl(
  309. FileObject,
  310. DeviceObject,
  311. &parameters,
  312. sizeof(parameters),
  313. NULL,
  314. 0,
  315. TDI_SET_EVENT_HANDLER,
  316. ClientIrp
  317. );
  318. return(status);
  319. } // CnpTdiSetEventHandler
  320. NTSTATUS
  321. CnpTdiErrorHandler(
  322. IN PVOID TdiEventContext,
  323. IN NTSTATUS Status
  324. )
  325. {
  326. return(STATUS_SUCCESS);
  327. } // CnpTdiErrorHandler
  328. VOID
  329. CnpAttachSystemProcess(
  330. VOID
  331. )
  332. /*++
  333. Routine Description:
  334. Attach to the system process, as determined during DriverEntry
  335. and stored in CnSystemProcess.
  336. Arguments:
  337. None.
  338. Return value:
  339. None.
  340. Notes:
  341. Must be followed by a call to CnpDetachSystemProcess.
  342. Implemented in this module due to header conflicts with
  343. ntddk.h.
  344. --*/
  345. {
  346. KeAttachProcess(CnSystemProcess);
  347. return;
  348. } // CnpAttachSystemProcess
  349. VOID
  350. CnpDetachSystemProcess(
  351. VOID
  352. )
  353. /*++
  354. Routine Description:
  355. Detach from the system process.
  356. Arguments:
  357. None.
  358. Return value:
  359. None.
  360. Notes:
  361. Must be preceded by a call to CnpDetachSystemProcess.
  362. Implemented in this module due to header conflicts with
  363. ntddk.h.
  364. --*/
  365. {
  366. KeDetachProcess();
  367. return;
  368. } // CnpDetachSystemProcess
  369. NTSTATUS
  370. CnpOpenDevice(
  371. IN LPWSTR DeviceName,
  372. OUT HANDLE *Handle
  373. )
  374. /*++
  375. Routine Description:
  376. Opens a handle to DeviceName. Since no EaBuffer is specified,
  377. CnpOpenDevice opens a control channel for TDI transports.
  378. Arguments:
  379. DeviceName - device to open
  380. Handle - resulting handle, NULL on failure
  381. Return Value:
  382. Status of ZwCreateFile
  383. Notes:
  384. Specifies OBJ_KERNEL_HANDLE, meaning that the resulting
  385. handle is only valid in kernel-mode. This routine
  386. cannot be called to obtain a handle that will be
  387. exported to user-mode.
  388. --*/
  389. {
  390. UNICODE_STRING nameString;
  391. OBJECT_ATTRIBUTES objectAttributes;
  392. IO_STATUS_BLOCK iosb;
  393. NTSTATUS status;
  394. PAGED_CODE();
  395. *Handle = (HANDLE) NULL;
  396. RtlInitUnicodeString(&nameString, DeviceName);
  397. InitializeObjectAttributes(
  398. &objectAttributes,
  399. &nameString,
  400. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  401. (HANDLE) NULL,
  402. (PSECURITY_DESCRIPTOR) NULL
  403. );
  404. status = ZwCreateFile(
  405. Handle,
  406. SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
  407. &objectAttributes,
  408. &iosb,
  409. NULL,
  410. FILE_ATTRIBUTE_NORMAL,
  411. FILE_SHARE_READ | FILE_SHARE_WRITE,
  412. FILE_OPEN_IF,
  413. 0,
  414. NULL,
  415. 0
  416. );
  417. if (!NT_SUCCESS(status)) {
  418. IF_CNDBG(CN_DEBUG_OPEN) {
  419. CNPRINT(("[Clusnet] Failed to open device %S, status %lx\n",
  420. DeviceName, status));
  421. }
  422. *Handle = NULL;
  423. }
  424. return(status);
  425. } // CnpOpenDevice
  426. NTSTATUS
  427. CnpZwDeviceControl(
  428. IN HANDLE Handle,
  429. IN ULONG IoControlCode,
  430. IN PVOID InputBuffer,
  431. IN ULONG InputBufferLength,
  432. IN PVOID OutputBuffer,
  433. IN ULONG OutputBufferLength
  434. )
  435. {
  436. NTSTATUS status = STATUS_SUCCESS;
  437. IO_STATUS_BLOCK iosb;
  438. HANDLE event;
  439. PAGED_CODE();
  440. status = ZwCreateEvent( &event,
  441. EVENT_ALL_ACCESS,
  442. NULL,
  443. SynchronizationEvent,
  444. FALSE );
  445. if (NT_SUCCESS(status)) {
  446. status = ZwDeviceIoControlFile(
  447. Handle,
  448. event,
  449. NULL,
  450. NULL,
  451. &iosb,
  452. IoControlCode,
  453. InputBuffer,
  454. InputBufferLength,
  455. OutputBuffer,
  456. OutputBufferLength
  457. );
  458. if (status == STATUS_PENDING) {
  459. status = ZwWaitForSingleObject( event, FALSE, NULL );
  460. CnAssert( status == STATUS_SUCCESS );
  461. status = iosb.Status;
  462. }
  463. ZwClose( event );
  464. }
  465. return(status);
  466. } // CnpZwDeviceControl
  467. #define TCP_SET_INFO_EX_BUFFER_PREALLOCSIZE 16
  468. #define TCP_SET_INFO_EX_PREALLOCSIZE \
  469. (FIELD_OFFSET(TCP_REQUEST_SET_INFORMATION_EX, Buffer) \
  470. + TCP_SET_INFO_EX_BUFFER_PREALLOCSIZE \
  471. )
  472. NTSTATUS
  473. CnpSetTcpInfoEx(
  474. IN HANDLE Handle,
  475. IN ULONG Entity,
  476. IN ULONG Class,
  477. IN ULONG Type,
  478. IN ULONG Id,
  479. IN PVOID Value,
  480. IN ULONG ValueLength
  481. )
  482. {
  483. NTSTATUS status;
  484. PTCP_REQUEST_SET_INFORMATION_EX setInfoEx;
  485. UCHAR infoBuf[TCP_SET_INFO_EX_PREALLOCSIZE]={0};
  486. PAGED_CODE();
  487. //
  488. // Check if we need to dynamically allocate.
  489. //
  490. if (ValueLength > TCP_SET_INFO_EX_BUFFER_PREALLOCSIZE) {
  491. setInfoEx = CnAllocatePool(
  492. FIELD_OFFSET(TCP_REQUEST_SET_INFORMATION_EX, Buffer)
  493. + ValueLength
  494. );
  495. if (setInfoEx == NULL) {
  496. return(STATUS_INSUFFICIENT_RESOURCES);
  497. }
  498. RtlZeroMemory(
  499. setInfoEx,
  500. FIELD_OFFSET(TCP_REQUEST_SET_INFORMATION_EX, Buffer) + ValueLength
  501. );
  502. } else {
  503. setInfoEx = (PTCP_REQUEST_SET_INFORMATION_EX)&infoBuf[0];
  504. }
  505. setInfoEx->ID.toi_entity.tei_entity = Entity;
  506. setInfoEx->ID.toi_entity.tei_instance = 0;
  507. setInfoEx->ID.toi_class = Class;
  508. setInfoEx->ID.toi_type = Type;
  509. setInfoEx->ID.toi_id = Id;
  510. setInfoEx->BufferSize = ValueLength;
  511. RtlCopyMemory(setInfoEx->Buffer, Value, ValueLength);
  512. status = CnpZwDeviceControl(
  513. Handle,
  514. IOCTL_TCP_SET_INFORMATION_EX,
  515. setInfoEx,
  516. FIELD_OFFSET(TCP_REQUEST_SET_INFORMATION_EX, Buffer)
  517. + ValueLength,
  518. NULL,
  519. 0
  520. );
  521. //
  522. // Free the buffer, if dynamically allocated
  523. //
  524. if (setInfoEx != (PTCP_REQUEST_SET_INFORMATION_EX)&infoBuf[0]) {
  525. CnFreePool(setInfoEx);
  526. }
  527. return(status);
  528. } // CnpSetTcpInfoEx
  529. NTSTATUS
  530. CnpInitializeSaltGenerator(
  531. VOID
  532. )
  533. /*++
  534. Routine Description:
  535. Initialize the FIPS-based random number generator.
  536. --*/
  537. {
  538. BOOL success;
  539. ULONG retries = 5;
  540. do {
  541. success = CxFipsFunctionTable.FIPSGenRandom(
  542. (PUCHAR) &CnpSaltBase,
  543. sizeof(CnpSaltBase)
  544. );
  545. } while (!success && retries--);
  546. return ((success) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
  547. } // CnpInitializeSaltGenerator
  548. VOID
  549. CnpGenerateSalt(
  550. IN PVOID SaltBuffer,
  551. IN ULONG SaltBufferLength
  552. )
  553. /*++
  554. Routine Description:
  555. Produce a salt.
  556. Assumptions: The salt produced in this routine does not
  557. need to be unpredictable. It just needs to be different.
  558. It will not be used as a key. It is intended to introduce
  559. greater variation into signed messages, because data
  560. typically signed by this algorithm differs by only a few
  561. bits (e.g. heartbeat sequence numbers, RGP flooded packets).
  562. Ideally, the FIPS random number generator would be used
  563. to produce as-random-as-possible numbers, but it cannot
  564. be called at DISPATCH_LEVEL. Therefore, we use the
  565. following algorithm:
  566. - Seed the 64-bit salt base with the FIPS RNG
  567. - Each time this routine is called, multiply the salt base
  568. by a prime number. This multiplication is not synchronized
  569. (e.g. with InterlockedXXX or a spinlock) because we don't
  570. really care if it is.
  571. - Add the current interrupt time to introduce a modicum of
  572. unpredictability.
  573. Arguments:
  574. SaltBuffer - allocated buffer for salt, possibly unaligned
  575. SaltBufferLength - length in bytes of SaltBuffer
  576. Return value:
  577. None.
  578. --*/
  579. {
  580. ULONG bufIndex;
  581. ULONG remaining;
  582. for (bufIndex = 0, remaining = SaltBufferLength - bufIndex;
  583. remaining > 0;
  584. bufIndex += sizeof(ULONGLONG), remaining -= sizeof(ULONGLONG)) {
  585. ULONGLONG salt;
  586. salt = (CnpSaltBase *= (ULONG)CNP_SALTBASE_MULTIPLIER);
  587. salt += KeQueryInterruptTime() + 1;
  588. RtlCopyMemory(
  589. (PUCHAR)SaltBuffer + bufIndex,
  590. (PUCHAR)&salt,
  591. (remaining <= sizeof(salt)) ? remaining : sizeof(salt)
  592. );
  593. }
  594. return;
  595. } // CnpGenerateSalt
  596. NTSTATUS
  597. CnpMakeSignature(
  598. IN PSecBufferDesc Data,
  599. IN PVOID Key,
  600. IN ULONG KeyLength,
  601. IN OPTIONAL PVOID SigBuffer,
  602. IN OPTIONAL ULONG SigBufferLength,
  603. OUT OPTIONAL PSecBuffer * SigSecBuffer,
  604. OUT OPTIONAL ULONG * SigLen
  605. )
  606. /*++
  607. Routine Description:
  608. Builds a signature for Data.
  609. Arguments:
  610. Data - data to be signed, packaged in a SecBufferDesc. All
  611. SecBuffers in Data should be of type SECBUFFER_DATA
  612. except exactly one which has type SECBUFFER_TOKEN.
  613. Other buffers will be ignored.
  614. Key - authentication key
  615. KeyLength - length of Key in bytes
  616. SigBuffer - Buffer in which to place completed signature. If NULL,
  617. signature is written into signature secbuffer (has
  618. type SECBUFFER_TOKEN in Data).
  619. SigBufferLength - length of buffer at SigBuffer, if provided
  620. SigSecBuffer - If non-NULL, returns pointer to signature secbuffer
  621. from Data.
  622. SigLen - on success, contains length of signature written
  623. on SEC_E_BUFFER_TOO_SMALL, contains required signature length
  624. undefined otherwise
  625. Return value:
  626. SEC_E_OK if successful.
  627. SEC_E_SECPKG_NOT_FOUND if the security buffer version is wrong.
  628. SEC_E_BUFFER_TOO_SMALL if SigBufferLength is too small.
  629. SEC_E_INVALID_TOKEN if Data is a misformed SecBuffer.
  630. --*/
  631. {
  632. A_SHA_CTX shaCtxt;
  633. PUCHAR hashBuffer;
  634. ULONG bufIndex;
  635. PSecBuffer sigSecBuffer = NULL;
  636. PSecBuffer curBuffer;
  637. ULONG status;
  638. //
  639. // Verify the version.
  640. //
  641. if (Data->ulVersion != SECBUFFER_VERSION) {
  642. status = SEC_E_SECPKG_NOT_FOUND;
  643. goto error_exit;
  644. }
  645. //
  646. // Verify that the provided sig buffer is big enough.
  647. //
  648. if (SigBuffer != NULL && SigBufferLength < CX_SIGNATURE_LENGTH) {
  649. status = SEC_E_BUFFER_TOO_SMALL;
  650. goto error_exit;
  651. }
  652. //
  653. // Initialize the SHA context.
  654. //
  655. CxFipsFunctionTable.FipsHmacSHAInit(&shaCtxt, (PUCHAR) Key, KeyLength);
  656. //
  657. // Hash the data.
  658. //
  659. for (bufIndex = 0, curBuffer = &(Data->pBuffers[bufIndex]);
  660. bufIndex < Data->cBuffers;
  661. bufIndex++, curBuffer++) {
  662. //
  663. // Process this buffer according to its type.
  664. //
  665. if (curBuffer->BufferType == SECBUFFER_DATA) {
  666. //
  667. // Hash this buffer.
  668. //
  669. CxFipsFunctionTable.FipsHmacSHAUpdate(
  670. &shaCtxt,
  671. (PUCHAR) curBuffer->pvBuffer,
  672. curBuffer->cbBuffer
  673. );
  674. } else if (curBuffer->BufferType == SECBUFFER_TOKEN) {
  675. if (sigSecBuffer != NULL) {
  676. //
  677. // There can only be one signature buffer per message.
  678. //
  679. status = SEC_E_INVALID_TOKEN;
  680. goto error_exit;
  681. } else {
  682. sigSecBuffer = curBuffer;
  683. //
  684. // Verify that the signature buffer is big enough.
  685. //
  686. if (sigSecBuffer->cbBuffer < CX_SIGNATURE_LENGTH) {
  687. *SigLen = CX_SIGNATURE_LENGTH;
  688. status = SEC_E_BUFFER_TOO_SMALL;
  689. goto error_exit;
  690. }
  691. //
  692. // Set the output buffer.
  693. //
  694. if (SigBuffer == NULL) {
  695. hashBuffer = sigSecBuffer->pvBuffer;
  696. } else {
  697. hashBuffer = SigBuffer;
  698. }
  699. }
  700. }
  701. }
  702. //
  703. // Verify that we found a buffer for the signature.
  704. //
  705. if (sigSecBuffer == NULL) {
  706. status = SEC_E_INVALID_TOKEN;
  707. goto error_exit;
  708. }
  709. //
  710. // Complete the hash.
  711. //
  712. CxFipsFunctionTable.FipsHmacSHAFinal(
  713. &shaCtxt,
  714. (PUCHAR) Key,
  715. KeyLength,
  716. hashBuffer
  717. );
  718. //
  719. // Return the signature buffer and length.
  720. //
  721. if (SigSecBuffer != NULL) {
  722. *SigSecBuffer = sigSecBuffer;
  723. }
  724. if (SigLen != NULL) {
  725. *SigLen = CX_SIGNATURE_LENGTH;
  726. }
  727. status = SEC_E_OK;
  728. error_exit:
  729. return(status);
  730. } // CnpMakeSignature
  731. NTSTATUS
  732. CnpVerifySignature(
  733. IN PSecBufferDesc Data,
  734. IN PVOID Key,
  735. IN ULONG KeyLength
  736. )
  737. /*++
  738. Routine Description:
  739. Verifies a signature for data.
  740. Arguments:
  741. Data - data to be verified, packaged in a SecBufferDesc. All
  742. SecBuffers in Data should be of type SECBUFFER_DATA
  743. except exactly one which has type SECBUFFER_TOKEN.
  744. Other buffers will be ignored.
  745. Key - authentication key
  746. KeyLength - length of Key in bytes
  747. Return value:
  748. SEC_E_OK if the signature is correct.
  749. SEC_E_SECPKG_NOT_FOUND if the security buffer version is wrong.
  750. SEC_E_INVALID_TOKEN if Data is a misformed SecBuffer.
  751. SEC_E_MESSAGE_ALTERED if signature is incorrect (including if it
  752. is the wrong length).
  753. --*/
  754. {
  755. UCHAR hashBuffer[CX_SIGNATURE_LENGTH];
  756. PSecBuffer sigBuffer = NULL;
  757. ULONG status;
  758. status = CnpMakeSignature(
  759. Data,
  760. Key,
  761. KeyLength,
  762. hashBuffer,
  763. sizeof(hashBuffer),
  764. &sigBuffer,
  765. NULL
  766. );
  767. if (status == SEC_E_OK) {
  768. //
  769. // Compare the generated signature to the provided signature.
  770. //
  771. if (RtlCompareMemory(
  772. hashBuffer,
  773. sigBuffer->pvBuffer,
  774. CX_SIGNATURE_LENGTH
  775. ) != sigBuffer->cbBuffer) {
  776. status = SEC_E_MESSAGE_ALTERED;
  777. } else {
  778. status = SEC_E_OK;
  779. }
  780. }
  781. return(status);
  782. } // CnpVerifySignature
  783. #define CNP_SIGN_SIGSECBUFS 3
  784. #define CNP_VRFY_SIGSECBUFS 2
  785. NTSTATUS
  786. CnpSignMulticastMessage(
  787. IN PCNP_SEND_REQUEST SendRequest,
  788. IN PMDL DataMdl,
  789. IN OUT CL_NETWORK_ID * NetworkId,
  790. OUT OPTIONAL ULONG * SigDataLen
  791. )
  792. /*++
  793. Routine Description:
  794. Sign a message.
  795. If NetworkId is not ClusterAnyNetworkId, the mcast group
  796. field must be set (and already referenced) in the SendRequest.
  797. This is the group that will be used to send the packet.
  798. The signature will be calculated in the order in which
  799. we provide SecBuffers. We need to make sure that order
  800. is the same on the sending side as it is on the receiving
  801. side. In order to make the signing and verifying more
  802. efficient, we prefer to sign and verify contiguous data
  803. in one chunk. Thus, we prepend the Salt (generated here)
  804. to the upper protocol header, allowing us to sign and verify
  805. the salt with that header. Thus, the layout of the message
  806. is as follows:
  807. MAC / IP / UDP Headers --
  808. |
  809. CNP Header |
  810. - not signed
  811. - CNP Signature Data |
  812. |
  813. - Signature |
  814. ==
  815. - Salt |
  816. |
  817. Upper Protocol Header (CDP or CCMP) - signed
  818. |
  819. Data --
  820. Note: Signing and verifying the Salt in the same chunk
  821. as the upper protocol header requires that they be
  822. contiguous. There can be no extra padding between
  823. the salt buffer and the start of the header.
  824. Arguments:
  825. SendRequest - send request, used to locate the upper protocol
  826. header to sign, as well as the signature buffer.
  827. DataMdl - data to sign
  828. NetworkId - IN: network on which to send the message, or
  829. ClusterAnyNetworkId if it should be chosen
  830. OUT: network id chosen to send packet
  831. SigDataLen - OUT (OPTIONAL): number of bytes occupied in
  832. message by signature data and signature
  833. --*/
  834. {
  835. NTSTATUS status;
  836. PCNP_NETWORK network;
  837. PCNP_MULTICAST_GROUP mcastGroup;
  838. BOOLEAN mcastGroupReferenced = FALSE;
  839. CNP_HEADER UNALIGNED * cnpHeader;
  840. CNP_SIGNATURE UNALIGNED * cnpSig;
  841. SecBufferDesc sigDescriptor;
  842. SecBuffer sigSecBufferPrealloc[CNP_SIGN_SIGSECBUFS];
  843. PSecBuffer sigSecBuffer = NULL;
  844. ULONG secBufferCount;
  845. ULONG sigLen;
  846. PMDL mdl;
  847. PSecBuffer curBuffer;
  848. CnAssert(SendRequest != NULL);
  849. CnAssert(SendRequest->UpperProtocolHeader == NULL ||
  850. SendRequest->UpperProtocolHeaderLength > 0);
  851. CnAssert(((CNP_HEADER UNALIGNED *)SendRequest->CnpHeader)->Version ==
  852. CNP_VERSION_MULTICAST);
  853. //
  854. // Determine which network to use.
  855. //
  856. if (*NetworkId != ClusterAnyNetworkId) {
  857. mcastGroup = SendRequest->McastGroup;
  858. CnAssert(mcastGroup != NULL);
  859. } else {
  860. network = CnpGetBestMulticastNetwork();
  861. if (network == NULL) {
  862. CnTrace(CNP_SEND_ERROR, CnpMcastGetBestNetwork,
  863. "[CNP] Failed to find best multicast network."
  864. );
  865. status = STATUS_NETWORK_UNREACHABLE;
  866. goto error_exit;
  867. }
  868. //
  869. // Get the network id and mcast group before releasing
  870. // the network lock.
  871. //
  872. *NetworkId = network->Id;
  873. mcastGroup = network->CurrentMcastGroup;
  874. if (mcastGroup == NULL) {
  875. CnTrace(CNP_SEND_ERROR, CnpMcastGroupNull,
  876. "[CNP] Best multicast network %u has null "
  877. "multicast group.",
  878. network->Id
  879. );
  880. CnReleaseLock(&(network->Lock), network->Irql);
  881. status = STATUS_NETWORK_UNREACHABLE;
  882. goto error_exit;
  883. }
  884. CnpReferenceMulticastGroup(mcastGroup);
  885. mcastGroupReferenced = TRUE;
  886. CnReleaseLock(&(network->Lock), network->Irql);
  887. }
  888. CnAssert(mcastGroup->SignatureLength == CX_SIGNATURE_LENGTH);
  889. //
  890. // Initialize the signature header.
  891. //
  892. cnpHeader = (CNP_HEADER UNALIGNED *)(SendRequest->CnpHeader);
  893. cnpSig = (CNP_SIGNATURE UNALIGNED *)(cnpHeader + 1);
  894. cnpSig->Version = CNP_SIG_VERSION_1;
  895. cnpSig->SigLength = CX_SIGNATURE_LENGTH;
  896. cnpSig->NetworkId = *NetworkId;
  897. cnpSig->ClusterNetworkBrand = mcastGroup->McastNetworkBrand;
  898. cnpSig->SaltLength = CX_SIGNATURE_SALT_LENGTH;
  899. //
  900. // Generate the salt. Write it into the SigDataBuffer field
  901. // of the header immediately after the signature.
  902. //
  903. CnpGenerateSalt(
  904. ((PUCHAR) &cnpSig->SigDataBuffer[CX_SIGNATURE_LENGTH]),
  905. CX_SIGNATURE_SALT_LENGTH
  906. );
  907. //
  908. // Determine how many sig sec buffers we will need.
  909. // The common case is three: one for a header and salt,
  910. // one for the data, and one for the signature.
  911. // We prealloc sig buffers on the stack
  912. // for the common case, but we dynamically allocate
  913. // if needed (e.g. if the data is a chain of MDLs).
  914. //
  915. secBufferCount = CNP_SIGN_SIGSECBUFS - 1;
  916. for (mdl = DataMdl; mdl != NULL; mdl = mdl->Next) {
  917. secBufferCount++;
  918. }
  919. //
  920. // Allocate the sig sec buffers.
  921. //
  922. if (secBufferCount <= CNP_SIGN_SIGSECBUFS) {
  923. sigSecBuffer = &sigSecBufferPrealloc[0];
  924. } else {
  925. sigSecBuffer = CnAllocatePool(
  926. secBufferCount * sizeof(SecBuffer)
  927. );
  928. if (sigSecBuffer == NULL) {
  929. status = STATUS_INSUFFICIENT_RESOURCES;
  930. goto error_exit;
  931. }
  932. }
  933. //
  934. // Prepare the descriptor for the message and signature.
  935. //
  936. sigDescriptor.cBuffers = secBufferCount;
  937. sigDescriptor.pBuffers = sigSecBuffer;
  938. sigDescriptor.ulVersion = SECBUFFER_VERSION;
  939. curBuffer = sigSecBuffer;
  940. //
  941. // Header and salt.
  942. //
  943. curBuffer->BufferType = SECBUFFER_DATA;
  944. curBuffer->pvBuffer = (PVOID) &cnpSig->SigDataBuffer[CX_SIGNATURE_LENGTH];
  945. curBuffer->cbBuffer = CX_SIGNATURE_SALT_LENGTH +
  946. SendRequest->UpperProtocolHeaderLength;
  947. curBuffer++;
  948. //
  949. // The payload provided by our client.
  950. //
  951. for (mdl = DataMdl; mdl != NULL; mdl = mdl->Next) {
  952. curBuffer->BufferType = SECBUFFER_DATA;
  953. curBuffer->cbBuffer = MmGetMdlByteCount(mdl);
  954. curBuffer->pvBuffer = MmGetMdlVirtualAddress(mdl);
  955. curBuffer++;
  956. }
  957. //
  958. // The Signature.
  959. //
  960. curBuffer->BufferType = SECBUFFER_TOKEN;
  961. curBuffer->pvBuffer = cnpSig->SigDataBuffer;
  962. curBuffer->cbBuffer = CX_SIGNATURE_LENGTH;
  963. status = CnpMakeSignature(
  964. &sigDescriptor,
  965. mcastGroup->Key,
  966. mcastGroup->KeyLength,
  967. NULL,
  968. 0,
  969. NULL,
  970. &sigLen
  971. );
  972. if (status != STATUS_SUCCESS || sigLen != CX_SIGNATURE_LENGTH) {
  973. IF_CNDBG(CN_DEBUG_CNPSEND) {
  974. CNPRINT(("[CNP] MakeSignature failed or returned "
  975. "an unexpected length, status %x, "
  976. "expected length %d, returned length %d.\n",
  977. status, CX_SIGNATURE_LENGTH, sigLen));
  978. }
  979. CnTrace(CNP_SEND_ERROR, CnpMcastMakeSigFailed,
  980. "[CNP] MakeSignature failed or returned "
  981. "an unexpected length, status %!status!, "
  982. "expected length %d, returned length %d.",
  983. status, CX_SIGNATURE_LENGTH, sigLen
  984. );
  985. status = STATUS_CLUSTER_NO_SECURITY_CONTEXT;
  986. }
  987. if (SigDataLen != NULL) {
  988. *SigDataLen = CNP_SIG_LENGTH(CX_SIGNATURE_DATA_LENGTH);
  989. }
  990. SendRequest->McastGroup = mcastGroup;
  991. error_exit:
  992. if (sigSecBuffer != NULL &&
  993. sigSecBuffer != &sigSecBufferPrealloc[0]) {
  994. CnFreePool(sigSecBuffer);
  995. sigSecBuffer = NULL;
  996. }
  997. if (status != STATUS_SUCCESS && mcastGroupReferenced) {
  998. CnAssert(mcastGroup != NULL);
  999. CnpDereferenceMulticastGroup(mcastGroup);
  1000. mcastGroupReferenced = FALSE;
  1001. }
  1002. return(status);
  1003. } // CnpSignMulticastMessage
  1004. NTSTATUS
  1005. CnpVerifyMulticastMessage(
  1006. IN PCNP_NETWORK Network,
  1007. IN PVOID Tsdu,
  1008. IN ULONG TsduLength,
  1009. IN ULONG ExpectedPayload,
  1010. OUT ULONG * BytesTaken,
  1011. OUT BOOLEAN * CurrentGroup
  1012. )
  1013. /*++
  1014. Routine Description:
  1015. Verify a message.
  1016. This routine assumes that the Salt in the CNP Signature
  1017. header is contiguous with the payload (most likely
  1018. consisting of a CDP or CCMP header followed by the
  1019. upper protocol payload). See the Routine Description
  1020. for CnpSignMulticastMessage for the expected layout of
  1021. the message data.
  1022. If, in a future release, it becomes necessary to extend
  1023. the space between the CNP Signature Header and the
  1024. payload (e.g. for alignment or whatever), the SigLength
  1025. can be increased. This routine will only compare
  1026. CX_SIGNATURE_LENGTH bytes of the signature buffer.
  1027. Arguments:
  1028. Network - network on which message arrived
  1029. Tsdu - points to protocol header
  1030. TsduLength - length of TSDU, including signature data
  1031. ExpectedPayload - expected payload after signature data
  1032. BytesTaken - OUT: quantity of data consumed by signature data
  1033. CurrentGroup - OUT: whether signature matched current
  1034. multicast group.
  1035. Return value:
  1036. SEC_E_OK or error status.
  1037. --*/
  1038. {
  1039. NTSTATUS status;
  1040. CNP_SIGNATURE UNALIGNED * cnpSig = Tsdu;
  1041. ULONG totalSigBytes = 0;
  1042. PVOID saltAndPayload;
  1043. ULONG saltAndPayloadLength;
  1044. PCNP_MULTICAST_GROUP currMcastGroup = NULL;
  1045. PCNP_MULTICAST_GROUP prevMcastGroup = NULL;
  1046. SecBufferDesc sigDescriptor;
  1047. SecBuffer sigSecBufferPrealloc[CNP_VRFY_SIGSECBUFS];
  1048. PSecBuffer sigSecBuffer = NULL;
  1049. PSecBuffer curBuffer;
  1050. //
  1051. // Verify that the signature is present. Do not
  1052. // dereference any signature data until we know
  1053. // it's there.
  1054. //
  1055. if (
  1056. // Verify that signature header data is present.
  1057. (TsduLength < (ULONG)CNP_SIGHDR_LENGTH) ||
  1058. // Verify that signature length and salt lengths are
  1059. // separately reasonable.
  1060. // This check prevents an overflow attack in which the
  1061. // sum of the lengths looks okay but individually they
  1062. // are invalid.
  1063. (TsduLength < cnpSig->SigLength) ||
  1064. (TsduLength < cnpSig->SaltLength) ||
  1065. // Verify that aggregate signature buffer is present
  1066. (TsduLength <
  1067. (totalSigBytes = CNP_SIG_LENGTH(cnpSig->SigLength + cnpSig->SaltLength))
  1068. ) ||
  1069. // Verify that the expected payload is present
  1070. (TsduLength - totalSigBytes != ExpectedPayload)
  1071. ) {
  1072. IF_CNDBG(CN_DEBUG_CNPRECV) {
  1073. CNPRINT(("[CNP] Cannot verify mcast packet with "
  1074. "mis-sized payload: TsduLength %u, required "
  1075. "sig hdr %u, sig data length %u, "
  1076. "expected payload %u.\n",
  1077. TsduLength,
  1078. CNP_SIGHDR_LENGTH,
  1079. totalSigBytes,
  1080. ExpectedPayload
  1081. ));
  1082. }
  1083. CnTrace(CNP_RECV_ERROR, CnpTraceReceiveTooSmall,
  1084. "[CNP] Cannot verify mcast packet with "
  1085. "undersized payload: TsduLength %u, required "
  1086. "sig hdr %u, sig buffer %u, "
  1087. "expected payload %u.\n",
  1088. TsduLength,
  1089. CNP_SIGHDR_LENGTH,
  1090. totalSigBytes,
  1091. ExpectedPayload
  1092. );
  1093. //
  1094. // Drop it.
  1095. //
  1096. status = SEC_E_INCOMPLETE_MESSAGE;
  1097. goto error_exit;
  1098. }
  1099. //
  1100. // Verify that the signature protocol is understood.
  1101. //
  1102. if (cnpSig->Version != CNP_SIG_VERSION_1) {
  1103. IF_CNDBG(CN_DEBUG_CNPRECV) {
  1104. CNPRINT(("[CNP] Cannot verify mcast packet with "
  1105. "unknown signature version: %u.\n",
  1106. cnpSig->Version
  1107. ));
  1108. }
  1109. CnTrace(
  1110. CNP_RECV_ERROR, CnpTraceRecvUnknownSigVersion,
  1111. "[CNP] Cannot verify mcast packet with "
  1112. "unknown signature version: %u.",
  1113. cnpSig->Version
  1114. );
  1115. //
  1116. // Drop it.
  1117. //
  1118. status = SEC_E_BAD_PKGID;
  1119. goto error_exit;
  1120. }
  1121. //
  1122. // Lock the network object and reference the
  1123. // multicast groups.
  1124. //
  1125. CnAcquireLock(&(Network->Lock), &(Network->Irql));
  1126. currMcastGroup = Network->CurrentMcastGroup;
  1127. if (currMcastGroup != NULL) {
  1128. CnpReferenceMulticastGroup(currMcastGroup);
  1129. }
  1130. prevMcastGroup = Network->PreviousMcastGroup;
  1131. if (prevMcastGroup != NULL) {
  1132. CnpReferenceMulticastGroup(prevMcastGroup);
  1133. }
  1134. CnReleaseLock(&(Network->Lock), Network->Irql);
  1135. //
  1136. // Verify that the packet network id matches the
  1137. // local network object.
  1138. //
  1139. if (cnpSig->NetworkId != Network->Id) {
  1140. IF_CNDBG(CN_DEBUG_CNPRECV) {
  1141. CNPRINT(("[CNP] Mcast packet has bad network "
  1142. "id: found %d, expected %d.\n",
  1143. cnpSig->NetworkId,
  1144. Network->Id
  1145. ));
  1146. }
  1147. CnTrace(
  1148. CNP_RECV_ERROR, CnpTraceReceiveBadNetworkId,
  1149. "[CNP] Mcast packet has bad network id: "
  1150. "found %d, expected %d.",
  1151. cnpSig->NetworkId,
  1152. Network->Id
  1153. );
  1154. //
  1155. // Drop it.
  1156. //
  1157. status = SEC_E_TARGET_UNKNOWN;
  1158. goto error_exit;
  1159. }
  1160. //
  1161. // Verify that the brand matches either the current or
  1162. // previous multicast group.
  1163. //
  1164. if (currMcastGroup != NULL &&
  1165. cnpSig->ClusterNetworkBrand != currMcastGroup->McastNetworkBrand) {
  1166. // can't use currMcastGroup
  1167. CnpDereferenceMulticastGroup(currMcastGroup);
  1168. currMcastGroup = NULL;
  1169. }
  1170. if (prevMcastGroup != NULL &&
  1171. cnpSig->ClusterNetworkBrand != prevMcastGroup->McastNetworkBrand) {
  1172. // can't use prevMcastGroup
  1173. CnpDereferenceMulticastGroup(prevMcastGroup);
  1174. prevMcastGroup = NULL;
  1175. }
  1176. if (currMcastGroup == NULL && prevMcastGroup == NULL) {
  1177. IF_CNDBG(CN_DEBUG_CNPRECV) {
  1178. CNPRINT(("[CNP] Recv'd mcast packet with brand %x, "
  1179. "but no matching multicast groups.\n",
  1180. cnpSig->ClusterNetworkBrand
  1181. ));
  1182. }
  1183. CnTrace(
  1184. CNP_RECV_ERROR, CnpTraceReceiveBadBrand,
  1185. "[CNP] Recv'd mcast packet with brand %x, "
  1186. "but no matching multicast groups.",
  1187. cnpSig->ClusterNetworkBrand
  1188. );
  1189. //
  1190. // Drop it.
  1191. //
  1192. status = SEC_E_TARGET_UNKNOWN;
  1193. goto error_exit;
  1194. }
  1195. //
  1196. // Locate the salt and payload following the signature data.
  1197. // The salt and payload are contiguous, and this is where we
  1198. // start with signature verification.
  1199. //
  1200. saltAndPayload = (PVOID)(&cnpSig->SigDataBuffer[cnpSig->SigLength]);
  1201. saltAndPayloadLength =
  1202. TsduLength - (PtrToUlong(saltAndPayload) - PtrToUlong(Tsdu));
  1203. //
  1204. // Build the signature descriptor for verification. The bytes
  1205. // that were signed (and hence need to be verified) include
  1206. // the salt (placed between the signature and the payload data)
  1207. // and the payload data.
  1208. //
  1209. sigSecBuffer = &sigSecBufferPrealloc[0];
  1210. curBuffer = sigSecBuffer;
  1211. sigDescriptor.cBuffers = CNP_VRFY_SIGSECBUFS - 1;
  1212. sigDescriptor.pBuffers = sigSecBuffer;
  1213. sigDescriptor.ulVersion = SECBUFFER_VERSION;
  1214. //
  1215. // Place the signature first in the sigDescriptor array. The
  1216. // order doesn't matter for correctness, but this way the
  1217. // signature token buffer will be validated before any
  1218. // computationally expensive hashing is performed.
  1219. //
  1220. curBuffer->BufferType = SECBUFFER_TOKEN;
  1221. curBuffer->cbBuffer = cnpSig->SigLength;
  1222. curBuffer->pvBuffer = (PVOID)&(cnpSig->SigDataBuffer[0]);
  1223. curBuffer++;
  1224. //
  1225. // Data.
  1226. //
  1227. if (saltAndPayloadLength > 0) {
  1228. sigDescriptor.cBuffers = CNP_VRFY_SIGSECBUFS;
  1229. curBuffer->BufferType = SECBUFFER_DATA;
  1230. curBuffer->cbBuffer = saltAndPayloadLength;
  1231. curBuffer->pvBuffer = saltAndPayload;
  1232. curBuffer++;
  1233. }
  1234. /*CNPRINT(("[CNP] Verifying message of length %d with "
  1235. "sig of length %d.\n",
  1236. HeaderLength + payloadLength,
  1237. cnpSig->SigBufferLen));*/
  1238. //
  1239. // Try the current multicast group, and if necessary,
  1240. // the previous multicast group.
  1241. //
  1242. status = SEC_E_INVALID_TOKEN;
  1243. if (currMcastGroup != NULL) {
  1244. status = CnpVerifySignature(
  1245. &sigDescriptor,
  1246. currMcastGroup->Key,
  1247. currMcastGroup->KeyLength
  1248. );
  1249. if (status == SEC_E_OK && CurrentGroup != NULL) {
  1250. *CurrentGroup = TRUE;
  1251. }
  1252. }
  1253. if (status != SEC_E_OK && prevMcastGroup != NULL) {
  1254. status = CnpVerifySignature(
  1255. &sigDescriptor,
  1256. prevMcastGroup->Key,
  1257. prevMcastGroup->KeyLength
  1258. );
  1259. if (status == SEC_E_OK && CurrentGroup != NULL) {
  1260. *CurrentGroup = FALSE;
  1261. }
  1262. }
  1263. if (status == SEC_E_OK) {
  1264. *BytesTaken = totalSigBytes;
  1265. }
  1266. error_exit:
  1267. if (currMcastGroup != NULL) {
  1268. CnpDereferenceMulticastGroup(currMcastGroup);
  1269. }
  1270. if (prevMcastGroup != NULL) {
  1271. CnpDereferenceMulticastGroup(prevMcastGroup);
  1272. }
  1273. CnVerifyCpuLockMask(
  1274. 0, // Required
  1275. 0xFFFFFFFF, // Forbidden
  1276. 0 // Maximum
  1277. );
  1278. return(status);
  1279. } // CnpVerifyMulticastMessage