/// <summary> /// Calls VerifySignature SSPI API function to ensure that given signature /// is correct. /// Throws an exception if the call fails. /// </summary> /// <param name="phContext">Established security context handle.</param> /// <param name="contentBuffer">Content to check the signature for.</param> /// <param name="signature">Stream containing the signature.</param> public static void VerifySignature(SspiApi.SecHandle phContext, byte[] contentBuffer, byte[] signature) { SspiApi.SecBufferDescNative secDesc = new SspiApi.SecBufferDescNative(); SspiApi.SecBufferNative[] secBuffers = new SspiApi.SecBufferNative[2]; using (GCHandleKeeper pinnedSignature = new GCHandleKeeper(signature, GCHandleType.Pinned)) { // the first contains the signature secBuffers[0].BufferType = SspiApi.SECBUFFER_TOKEN; secBuffers[0].cbBuffer = signature.Length; secBuffers[0].pvBuffer = pinnedSignature.GCHandle.AddrOfPinnedObject(); using (GCHandleKeeper pinnedContentBuffer = new GCHandleKeeper(contentBuffer, GCHandleType.Pinned)) { // and pin it for signing secBuffers[1].BufferType = SspiApi.SECBUFFER_DATA; secBuffers[1].cbBuffer = contentBuffer.Length; secBuffers[1].pvBuffer = pinnedContentBuffer.GCHandle.AddrOfPinnedObject(); using (GCHandleKeeper pinnedSecBuffers = new GCHandleKeeper(secBuffers, GCHandleType.Pinned)) { // setup descriptor secDesc.ulVersion = SspiApi.SECBUFFER_VERSION; secDesc.cBuffers = 2; secDesc.pBuffers = pinnedSecBuffers.GCHandle.AddrOfPinnedObject(); int result = 0; int pfQOP = 0; if (_isNT) result = VerifySignature_NT(phContext, ref secDesc, 0, ref pfQOP); else result = VerifySignature__(phContext, ref secDesc, 0, ref pfQOP); if (result != SspiApi.SEC_E_OK) throw GenuineExceptions.Get_Windows_SspiError(result); } // pin sec buffers } // pin the content buffer } // pin the signature buffer }
/// <summary> /// Calls MakeSignature SSPI API function and saves obtained signature to /// outputSignature parameter. /// Throws an exception if the call fails. /// </summary> /// <param name="phContext">Established security context handle.</param> /// <param name="contentBuffer">Content to make signature for.</param> /// <param name="outputSignature">Output stream to write signature to.</param> /// <param name="secPkgContext_Sizes">Security context size constants.</param> public static void MakeSignature(SspiApi.SecHandle phContext, byte[] contentBuffer, BinaryWriter outputSignature, ref SecPkgContext_Sizes secPkgContext_Sizes) { SspiApi.SecBufferDescNative secDesc = new SspiApi.SecBufferDescNative(); SspiApi.SecBufferNative[] secBuffers = new SspiApi.SecBufferNative[2]; byte[] signBuffer = new byte[secPkgContext_Sizes.cbMaxSignature]; using (GCHandleKeeper pinnedSignBuffer = new GCHandleKeeper(signBuffer, GCHandleType.Pinned)) { // the first is for getting a sign secBuffers[0].BufferType = SspiApi.SECBUFFER_TOKEN; secBuffers[0].cbBuffer = secPkgContext_Sizes.cbMaxSignature; secBuffers[0].pvBuffer = pinnedSignBuffer.GCHandle.AddrOfPinnedObject(); // pin contentBuffer secBuffers[1].BufferType = SspiApi.SECBUFFER_DATA; secBuffers[1].cbBuffer = (int) contentBuffer.Length; using (GCHandleKeeper pinnedContentBuffer = new GCHandleKeeper(contentBuffer, GCHandleType.Pinned)) { secBuffers[1].pvBuffer = pinnedContentBuffer.GCHandle.AddrOfPinnedObject(); // setup descriptor secDesc.ulVersion = SspiApi.SECBUFFER_VERSION; secDesc.cBuffers = 2; using (GCHandleKeeper pinnedSecBuffers = new GCHandleKeeper(secBuffers, GCHandleType.Pinned)) { secDesc.pBuffers = pinnedSecBuffers.GCHandle.AddrOfPinnedObject(); int result = 0; if (_isNT) result = MakeSignature_NT(phContext, 0, ref secDesc, 0); else result = MakeSignature__(phContext, 0, ref secDesc, 0); if (result != SspiApi.SEC_E_OK) throw GenuineExceptions.Get_Windows_SspiError(result); outputSignature.Write(signBuffer, 0, secBuffers[0].cbBuffer); } // pin sec buffers } // pin the content buffer } // pin the signature buffer }
/// <summary> /// Calls InitializeSecurityContext SSPI API function. /// Throws an exception if the call fails. /// receivedData parameter must be null for the first call. /// </summary> /// <param name="credHandle">Credential handle.</param> /// <param name="inputPhContext">Source security context.</param> /// <param name="outputPhContext">Created security context.</param> /// <param name="targetName">Target name.</param> /// <param name="requiredFeatures">Requested features.</param> /// <param name="ptsExpiry">Expiry.</param> /// <param name="receivedData">Input data.</param> /// <param name="outputStream">Output data.</param> /// <returns>True if security context has been succesfully built up.</returns> public static bool InitializeSecurityContext(SspiApi.SecHandle credHandle, SspiApi.SecHandle inputPhContext, SspiApi.SecHandle outputPhContext, string targetName, SspiFeatureFlags requiredFeatures, ref Int64 ptsExpiry, Stream receivedData, Stream outputStream) { bool finalResult = false; // get the size of the received chunk int inputContentSize = 0; if (receivedData != null) { BinaryReader binaryReader = new BinaryReader(receivedData); inputContentSize = binaryReader.ReadInt32(); } SspiApi.SecBufferDescNative secInputDesc = new SspiApi.SecBufferDescNative(); SspiApi.SecBuffer secInputBuf = new SspiApi.SecBuffer(); SspiApi.SecBufferDescNative secOutputDesc = new SspiApi.SecBufferDescNative(); SspiApi.SecBuffer secOutputBuf = new SspiApi.SecBuffer(); IntPtr inputDescBuffer = IntPtr.Zero; IntPtr outputDescBuffer = IntPtr.Zero; #if TRIAL #else try { #endif inputDescBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SspiApi.SecBufferDescNative))); outputDescBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SspiApi.SecBufferDescNative))); // setup input buffer secInputDesc.ulVersion = SspiApi.SECBUFFER_VERSION; secInputDesc.cBuffers = 1; secInputDesc.pBuffers = inputDescBuffer; secInputBuf.BufferType = SspiApi.SECBUFFER_TOKEN; secInputBuf.cbBuffer = inputContentSize; if (inputContentSize > 0) { secInputBuf.pvBuffer = Marshal.AllocHGlobal(inputContentSize); // read from the stream byte[] content = new byte[inputContentSize]; GenuineUtility.ReadDataFromStream(receivedData, content, 0, inputContentSize); Marshal.Copy(content, 0, secInputBuf.pvBuffer, inputContentSize); } else secInputBuf.pvBuffer = IntPtr.Zero; Marshal.StructureToPtr(secInputBuf, inputDescBuffer, false); // setup output buffer secOutputDesc.ulVersion = SspiApi.SECBUFFER_VERSION; secOutputDesc.cBuffers = 1; secOutputDesc.pBuffers = outputDescBuffer; secOutputBuf.BufferType = SspiApi.SECBUFFER_TOKEN; secOutputBuf.cbBuffer = 0; secOutputBuf.pvBuffer = IntPtr.Zero; Marshal.StructureToPtr(secOutputBuf, outputDescBuffer, false); int fContextReq = SspiApi.ISC_REQ_REPLAY_DETECT | SspiApi.ISC_REQ_CONNECTION | SspiApi.ISC_REQ_ALLOCATE_MEMORY; if ((requiredFeatures & SspiFeatureFlags.Encryption) != 0) fContextReq |= SspiApi.ISC_REQ_CONFIDENTIALITY; if ((requiredFeatures & SspiFeatureFlags.Signing) != 0) fContextReq |= SspiApi.ISC_REQ_INTEGRITY; if ((requiredFeatures & SspiFeatureFlags.Delegation) != 0) fContextReq |= SspiApi.ISC_REQ_MUTUAL_AUTH | SspiApi.ISC_REQ_DELEGATE; int fContextAttr = 0; // initialize context int result = 0; if (_isNT) result = SspiApi.InitializeSecurityContext_NT(credHandle, inputPhContext, targetName, fContextReq, 0, SspiApi.SECURITY_NATIVE_DREP, ref secInputDesc, 0, outputPhContext, ref secOutputDesc, ref fContextAttr, ref ptsExpiry); else result = SspiApi.InitializeSecurityContext__(credHandle, inputPhContext, targetName, fContextReq, 0, SspiApi.SECURITY_NATIVE_DREP, ref secInputDesc, 0, outputPhContext, ref secOutputDesc, ref fContextAttr, ref ptsExpiry); #if DEBUG // GenuineLoggingServices.BinaryLogWriter.Log(LogMessageCategory.Notification, null, "SspiApi.InitializeSecurityContext", // null, "SSPI InitializeSecurityContext function returned {0:X}.", result); #endif // analyze the result if (result == SspiApi.SEC_E_OK) finalResult = true; else if (result == SspiApi.SEC_I_CONTINUE_NEEDED) finalResult = false; else throw GenuineExceptions.Get_Windows_SspiError(result); // bring out feature checking into security session built event if (finalResult) { // check whether all the requested features will be available if ((requiredFeatures & SspiFeatureFlags.Encryption) != 0 && (fContextAttr & SspiApi.ISC_REQ_CONFIDENTIALITY) == 0) throw GenuineExceptions.Get_Windows_SspiDidNotProvideRequestedFeature("SspiFeatureFlags.Encryption"); if ((requiredFeatures & SspiFeatureFlags.Signing) != 0 && (fContextAttr & SspiApi.ISC_REQ_INTEGRITY) == 0) throw GenuineExceptions.Get_Windows_SspiDidNotProvideRequestedFeature("SspiFeatureFlags.Signing"); if ((requiredFeatures & SspiFeatureFlags.Delegation) != 0 && (fContextAttr & SspiApi.ISC_REQ_DELEGATE) == 0) throw GenuineExceptions.Get_Windows_SspiDidNotProvideRequestedFeature("SspiFeatureFlags.Delegation"); } // copy received data from the buffer Marshal.PtrToStructure(outputDescBuffer, secOutputBuf); if (secOutputBuf.cbBuffer > 0) { // allocate memory chunk and write content byte[] content = new byte[secOutputBuf.cbBuffer]; Marshal.Copy(secOutputBuf.pvBuffer, content, 0, secOutputBuf.cbBuffer); // write it to the stream BinaryWriter binaryWriter = new BinaryWriter(outputStream); binaryWriter.Write((int) secOutputBuf.cbBuffer); binaryWriter.Write(content); } #if TRIAL #else } finally { // release allocated resources if (secInputBuf.pvBuffer != IntPtr.Zero) Marshal.FreeHGlobal(secInputBuf.pvBuffer); if (secOutputBuf.pvBuffer != IntPtr.Zero) SspiApi.FreeContextBuffer(secOutputBuf.pvBuffer); if (inputDescBuffer != IntPtr.Zero) Marshal.FreeHGlobal(inputDescBuffer); if (outputDescBuffer != IntPtr.Zero) Marshal.FreeHGlobal(outputDescBuffer); } #endif return finalResult; }
/// <summary> /// Calls EncryptMessage SSPI API function. /// Throws an exception if the call fails. /// </summary> /// <param name="phContext">Established security context handle.</param> /// <param name="sourceContent">Source data.</param> /// <param name="outputContent">Writer to write encrypted data to.</param> /// <param name="secPkgContext_Sizes">Current package's sizes.</param> public static void EncryptMessage(SspiApi.SecHandle phContext, Stream sourceContent, BinaryWriter outputContent, ref SecPkgContext_Sizes secPkgContext_Sizes) { SspiApi.SecBufferDescNative secDesc = new SspiApi.SecBufferDescNative(); // for token, data and padding SspiApi.SecBufferNative[] secBuffers = new SspiApi.SecBufferNative[3]; byte[] signature = new byte[secPkgContext_Sizes.cbSecurityTrailer]; byte[] message = new byte[(int) sourceContent.Length]; byte[] padding = new byte[secPkgContext_Sizes.cbBlockSize]; GenuineUtility.ReadDataFromStream(sourceContent, message, 0, message.Length); using (GCHandleKeeper pinnedSignature = new GCHandleKeeper(signature, GCHandleType.Pinned)) { // the first is for signature secBuffers[0].BufferType = SspiApi.SECBUFFER_TOKEN; secBuffers[0].cbBuffer = signature.Length; secBuffers[0].pvBuffer = pinnedSignature.GCHandle.AddrOfPinnedObject(); using (GCHandleKeeper pinnedMessage = new GCHandleKeeper(message, GCHandleType.Pinned)) { // the second contains data secBuffers[1].BufferType = SspiApi.SECBUFFER_DATA; secBuffers[1].cbBuffer = message.Length; secBuffers[1].pvBuffer = pinnedMessage.GCHandle.AddrOfPinnedObject(); using (GCHandleKeeper pinnedPadding = new GCHandleKeeper(padding, GCHandleType.Pinned)) { // the third is for padding secBuffers[2].BufferType = SspiApi.SECBUFFER_PADDING; secBuffers[2].cbBuffer = padding.Length; secBuffers[2].pvBuffer = pinnedPadding.GCHandle.AddrOfPinnedObject(); // setup descriptor secDesc.ulVersion = SspiApi.SECBUFFER_VERSION; secDesc.cBuffers = 3; using (GCHandleKeeper pinnedSecBuffers = new GCHandleKeeper(secBuffers, GCHandleType.Pinned)) { secDesc.pBuffers = pinnedSecBuffers.GCHandle.AddrOfPinnedObject(); // make the call int result = 0; if (_isNT) result = EncryptMessage_NT(phContext, 0, ref secDesc, 0); else result = EncryptMessage__(phContext, 0, ref secDesc, 0); if (result != SspiApi.SEC_E_OK) throw GenuineExceptions.Get_Windows_SspiError(result); } } } } // write sizes outputContent.Write( (int) secBuffers[0].cbBuffer ); outputContent.Write( (int) secBuffers[1].cbBuffer ); outputContent.Write( (int) secBuffers[2].cbBuffer ); // and content outputContent.Write( signature, 0, secBuffers[0].cbBuffer ); outputContent.Write( message, 0, secBuffers[1].cbBuffer ); outputContent.Write( padding, 0, secBuffers[2].cbBuffer ); }
/// <summary> /// Calls DecryptMessage SSPI API function. /// Throws an exception if the call fails. /// </summary> /// <param name="phContext">Established security context handle.</param> /// <param name="sourceContent">Stream containing encrypted data.</param> /// <returns>Stream containing decrypted data.</returns> public static Stream DecryptMessage(SspiApi.SecHandle phContext, BinaryReader sourceContent) { SspiApi.SecBufferDescNative secDesc = new SspiApi.SecBufferDescNative(); // for token, data and padding SspiApi.SecBufferNative[] secBuffers = new SspiApi.SecBufferNative[3]; // read sizes int signatureSize = sourceContent.ReadInt32(); int messageSize = sourceContent.ReadInt32(); int paddingSize = sourceContent.ReadInt32(); // allocate buffers byte[] signature = new byte[signatureSize]; byte[] message = new byte[messageSize]; byte[] padding = new byte[paddingSize]; // read content GenuineUtility.ReadDataFromStream(sourceContent.BaseStream, signature, 0, signatureSize); GenuineUtility.ReadDataFromStream(sourceContent.BaseStream, message, 0, messageSize); GenuineUtility.ReadDataFromStream(sourceContent.BaseStream, padding, 0, paddingSize); using (GCHandleKeeper pinnedSignature = new GCHandleKeeper(signature, GCHandleType.Pinned)) { // the first is for signature secBuffers[0].BufferType = SspiApi.SECBUFFER_TOKEN; secBuffers[0].cbBuffer = signatureSize; secBuffers[0].pvBuffer = pinnedSignature.GCHandle.AddrOfPinnedObject(); using (GCHandleKeeper pinnedMessage = new GCHandleKeeper(message, GCHandleType.Pinned)) { // the second contains data secBuffers[1].BufferType = SspiApi.SECBUFFER_DATA; secBuffers[1].cbBuffer = messageSize; secBuffers[1].pvBuffer = pinnedMessage.GCHandle.AddrOfPinnedObject(); using (GCHandleKeeper pinnedPadding = new GCHandleKeeper(padding, GCHandleType.Pinned)) { // the third is for padding secBuffers[2].BufferType = SspiApi.SECBUFFER_PADDING; secBuffers[2].cbBuffer = paddingSize; secBuffers[2].pvBuffer = pinnedPadding.GCHandle.AddrOfPinnedObject(); // setup descriptor secDesc.ulVersion = SspiApi.SECBUFFER_VERSION; secDesc.cBuffers = 3; using (GCHandleKeeper pinnedSecBuffers = new GCHandleKeeper(secBuffers, GCHandleType.Pinned)) { secDesc.pBuffers = pinnedSecBuffers.GCHandle.AddrOfPinnedObject(); // make the call int result = 0; int pfQOP = 0; if (_isNT) result = DecryptMessage_NT(phContext, ref secDesc, 0, ref pfQOP); else result = DecryptMessage__(phContext, ref secDesc, 0, ref pfQOP); if (result != SspiApi.SEC_E_OK) throw GenuineExceptions.Get_Windows_SspiError(result); } } } } // return the result return new MemoryStream(message, 0, secBuffers[1].cbBuffer, false, true); }
/// <summary> /// Calls AcquireCredentialsHandle SSPI API function. /// Throws an exception if the call fails. /// </summary> /// <param name="authIdentity">User credential.</param> /// <param name="packageName">Package name.</param> /// <param name="fCredentialUse">Exchange direction.</param> /// <param name="credHandle">Where to store credential handle.</param> /// <param name="ptsExpiry">Lifetime span.</param> public static void AcquireCredentialsHandle(NetworkCredential authIdentity, string packageName, int fCredentialUse, SspiApi.SecHandle credHandle, ref Int64 ptsExpiry) { SspiApi.SEC_WINNT_AUTH_IDENTITY sspiAuthIdentity = new SspiApi.SEC_WINNT_AUTH_IDENTITY(); #if TRIAL #else try { #endif // prepare identity structure if (authIdentity != null) { sspiAuthIdentity.Domain = Marshal.StringToCoTaskMemAuto(authIdentity.Domain); sspiAuthIdentity.User = Marshal.StringToCoTaskMemAuto(authIdentity.UserName); sspiAuthIdentity.Password = Marshal.StringToCoTaskMemAuto(authIdentity.Password); sspiAuthIdentity.DomainLength = authIdentity.Domain.Length; sspiAuthIdentity.UserLength = authIdentity.UserName.Length; sspiAuthIdentity.PasswordLength = authIdentity.Password.Length; sspiAuthIdentity.Flags = Marshal.SystemDefaultCharSize == 2 ? SspiApi.SEC_WINNT_AUTH_IDENTITY_UNICODE : SspiApi.SEC_WINNT_AUTH_IDENTITY_ANSI; } int result = 0; // make the call if (authIdentity != null) { if (_isNT) result = SspiApi.AcquireCredentialsHandleIdentity_NT(IntPtr.Zero, packageName, fCredentialUse, IntPtr.Zero, ref sspiAuthIdentity, IntPtr.Zero, IntPtr.Zero, credHandle, ref ptsExpiry); else result = SspiApi.AcquireCredentialsHandleIdentity__(IntPtr.Zero, packageName, fCredentialUse, IntPtr.Zero, ref sspiAuthIdentity, IntPtr.Zero, IntPtr.Zero, credHandle, ref ptsExpiry); } else { if (_isNT) result = SspiApi.AcquireCredentialsHandleIdentityNull_NT(IntPtr.Zero, packageName, fCredentialUse, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, credHandle, ref ptsExpiry); else result = SspiApi.AcquireCredentialsHandleIdentityNull__(IntPtr.Zero, packageName, fCredentialUse, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, credHandle, ref ptsExpiry); } if (result != SspiApi.SEC_E_OK) throw GenuineExceptions.Get_Windows_SspiError(result); #if TRIAL #else } finally { // release allocated memory if (sspiAuthIdentity.Domain != IntPtr.Zero) Marshal.FreeCoTaskMem(sspiAuthIdentity.Domain); if (sspiAuthIdentity.User != IntPtr.Zero) Marshal.FreeCoTaskMem(sspiAuthIdentity.User); if (sspiAuthIdentity.Password != IntPtr.Zero) Marshal.FreeCoTaskMem(sspiAuthIdentity.Password); } #endif }