/// <summary> /// Constructs an instance of the KeyProvider_SspiClient class. /// </summary> /// <param name="requiredFeatures">SSPI features that will be provided by the security session.</param> /// <param name="packageName">The name of the used SSPI package.</param> /// <param name="authIdentity">The authentication identity used during authentication.</param> /// <param name="targetName">The name of the server which will be the target of the context. See description of the InitializeSecurityContext function in Platform SDK Security.</param> /// <param name="delegatedContext">The context being delegated to the destination host.</param> public KeyProvider_SspiClient(SspiFeatureFlags requiredFeatures, SupportedSspiPackages packageName, NetworkCredential authIdentity, string targetName, SecuritySession_SspiServer delegatedContext) { this.RequiredFeatures = requiredFeatures; this.PackageName = Enum.Format(typeof(SupportedSspiPackages), packageName, "f"); this.AuthIdentity = authIdentity; this.ServerName = targetName; this.DelegatedContext = delegatedContext; }
/// <summary> /// Decrypts the data. /// </summary> /// <param name="sourceStream">Stream containing encrypted data.</param> /// <param name="sspiFeatureFlags">Requested SSPI features.</param> /// <returns>Stream containing decrypted data.</returns> public Stream DecryptMessage(Stream sourceStream, SspiFeatureFlags sspiFeatureFlags) { // get package sizes lock (_secPkgContext_SizesLock) { if (!_secPkgContext_SizesInitialized) { SspiApi.QueryContextSizes(this._phContext, ref this._secPkgContext_Sizes); _secPkgContext_SizesInitialized = true; } } BinaryReader messageReader = new BinaryReader(sourceStream); if ((sspiFeatureFlags & SspiFeatureFlags.Encryption) != 0) { // decrypt it return(SspiApi.DecryptMessage(this._phContext, messageReader)); } else if ((sspiFeatureFlags & SspiFeatureFlags.Signing) != 0) { // read signature int signatureSize = messageReader.ReadInt32(); byte[] signature = new byte[signatureSize]; GenuineUtility.ReadDataFromStream(sourceStream, signature, 0, signatureSize); // read content int contentSize = messageReader.ReadInt32(); byte[] content = new byte[contentSize]; GenuineUtility.ReadDataFromStream(sourceStream, content, 0, contentSize); // verify signature SspiApi.VerifySignature(this._phContext, content, signature); // return verified content return(new MemoryStream(content, 0, content.Length, false, true)); } return(sourceStream); }
/// <summary> /// Creates a Security Session. /// </summary> /// <param name="name">Security Session name.</param> /// <param name="securitySessionType">Security Session type.</param> /// <param name="sspiFeatureFlags">Requested features.</param> /// <param name="sspiPackage">SSPI package.</param> public void CreateSecuritySession(string name, SecuritySessionType securitySessionType, SspiFeatureFlags sspiFeatureFlags, SupportedSspiPackages sspiPackage) { IKeyProvider iKeyProvider = null; switch (securitySessionType) { case SecuritySessionType.Basic: iKeyProvider = new KeyProvider_Basic(); break; case SecuritySessionType.KnownSymmetric: SymmetricAlgorithm symmetricAlgorithm = SymmetricAlgorithm.Create(); // read the key Stream stream = typeof(IEstablishSecuritySession).Assembly.GetManifestResourceStream("Known.written_key"); byte[] key = new byte[32]; stream.Read(key, 0, key.Length); stream.Close(); // initialize the key symmetricAlgorithm.Key = key; symmetricAlgorithm.Mode = CipherMode.ECB; iKeyProvider = new KeyProvider_KnownSymmetric(symmetricAlgorithm); break; case SecuritySessionType.SelfEstablishingSymmetric: iKeyProvider = new KeyProvider_SelfEstablishingSymmetric(); break; case SecuritySessionType.Sspi: iKeyProvider = new KeyProvider_SspiServer(sspiFeatureFlags, sspiPackage); break; } // register the Security Session in the current Transport Context GenuineUtility.CurrentMessage.ITransportContext.IKeyStore.SetKey(name, iKeyProvider); this._currentSecuritySessionName = name; }
/// <summary> /// Decrypts the data. /// </summary> /// <param name="sourceStream">Stream containing encrypted data.</param> /// <param name="sspiFeatureFlags">Requested SSPI features.</param> /// <returns>Stream containing decrypted data.</returns> public Stream DecryptMessage(Stream sourceStream, SspiFeatureFlags sspiFeatureFlags) { // get package sizes lock(_secPkgContext_SizesLock) { if (! _secPkgContext_SizesInitialized) { SspiApi.QueryContextSizes(this._phContext, ref this._secPkgContext_Sizes); _secPkgContext_SizesInitialized = true; } } BinaryReader messageReader = new BinaryReader(sourceStream); if ( (sspiFeatureFlags & SspiFeatureFlags.Encryption) != 0) // decrypt it return SspiApi.DecryptMessage(this._phContext, messageReader); else if ( (sspiFeatureFlags & SspiFeatureFlags.Signing) != 0) { // read signature int signatureSize = messageReader.ReadInt32(); byte[] signature = new byte[signatureSize]; GenuineUtility.ReadDataFromStream(sourceStream, signature, 0, signatureSize); // read content int contentSize = messageReader.ReadInt32(); byte[] content = new byte[contentSize]; GenuineUtility.ReadDataFromStream(sourceStream, content, 0, contentSize); // verify signature SspiApi.VerifySignature(this._phContext, content, signature); // return verified content return new MemoryStream(content, 0, content.Length, false, true); } return sourceStream; }
/// <summary> /// Encrypts the stream under current security conditions. /// </summary> /// <param name="messageStream">Data to be encrypted.</param> /// <param name="outputStream">Stream to write encrypted content to.</param> /// <param name="sspiFeatureFlags">Requested features.</param> public void EncryptMessage(Stream messageStream, GenuineChunkedStream outputStream, SspiFeatureFlags sspiFeatureFlags) { // get package sizes lock (_secPkgContext_SizesLock) { if (!_secPkgContext_SizesInitialized) { SspiApi.QueryContextSizes(this._phContext, ref this._secPkgContext_Sizes); _secPkgContext_SizesInitialized = true; } } byte[] chunk = null; int position = 0; BinaryWriter outputWriter = new BinaryWriter(outputStream); if ((sspiFeatureFlags & SspiFeatureFlags.Encryption) != 0) { // it'll write signature automatically as well as encrypt content SspiApi.EncryptMessage(this._phContext, messageStream, outputWriter, ref this._secPkgContext_Sizes); } else if ((sspiFeatureFlags & SspiFeatureFlags.Signing) != 0) { // remember position to write signature size later outputStream.WriteInt32AndRememberItsLocation(0, out chunk, out position); long currentLength = outputStream.Length; // anyway will have to read this into buffer byte[] contentBuffer = new byte[(int)messageStream.Length]; GenuineUtility.ReadDataFromStream(messageStream, contentBuffer, 0, contentBuffer.Length); // write signature SspiApi.MakeSignature(this._phContext, contentBuffer, outputWriter, ref this._secPkgContext_Sizes); // update signature size MessageCoder.WriteInt32(chunk, position, (int)(outputStream.Length - currentLength)); // write the content outputWriter.Write((int)contentBuffer.Length); outputWriter.Write(contentBuffer, 0, contentBuffer.Length); } else { // just copy the source content //outputWriter.Write( (int) messageStream.Length ); GenuineUtility.CopyStreamToStream(messageStream, outputStream); } }
/// <summary> /// Encrypts the stream under current security conditions. /// </summary> /// <param name="messageStream">Data to be encrypted.</param> /// <param name="outputStream">Stream to write encrypted content to.</param> /// <param name="sspiFeatureFlags">Requested features.</param> public void EncryptMessage(Stream messageStream, GenuineChunkedStream outputStream, SspiFeatureFlags sspiFeatureFlags) { // get package sizes lock(_secPkgContext_SizesLock) { if (! _secPkgContext_SizesInitialized) { SspiApi.QueryContextSizes(this._phContext, ref this._secPkgContext_Sizes); _secPkgContext_SizesInitialized = true; } } byte[] chunk = null; int position = 0; BinaryWriter outputWriter = new BinaryWriter(outputStream); if ( (sspiFeatureFlags & SspiFeatureFlags.Encryption) != 0) // it'll write signature automatically as well as encrypt content SspiApi.EncryptMessage(this._phContext, messageStream, outputWriter, ref this._secPkgContext_Sizes); else if ( (sspiFeatureFlags & SspiFeatureFlags.Signing) != 0) { // remember position to write signature size later outputStream.WriteInt32AndRememberItsLocation(0, out chunk, out position); long currentLength = outputStream.Length; // anyway will have to read this into buffer byte[] contentBuffer = new byte[(int) messageStream.Length]; GenuineUtility.ReadDataFromStream(messageStream, contentBuffer, 0, contentBuffer.Length); // write signature SspiApi.MakeSignature(this._phContext, contentBuffer, outputWriter, ref this._secPkgContext_Sizes); // update signature size MessageCoder.WriteInt32(chunk, position, (int) (outputStream.Length - currentLength) ); // write the content outputWriter.Write( (int) contentBuffer.Length ); outputWriter.Write( contentBuffer, 0, contentBuffer.Length); } else { // just copy the source content //outputWriter.Write( (int) messageStream.Length ); GenuineUtility.CopyStreamToStream(messageStream, outputStream); } }
/// <summary> /// Constructs an instance of the KeyProvider_SspiServer class. /// </summary> /// <param name="requiredFeatures">SSPI features that will be provided by Security Sessions.</param> /// <param name="packageName">The name of the used SSPI package.</param> public KeyProvider_SspiServer(SspiFeatureFlags requiredFeatures, SupportedSspiPackages packageName) { this.RequiredFeatures = requiredFeatures; this.PackageName = Enum.Format(typeof(SupportedSspiPackages), packageName, "f"); }
/// <summary> /// Constructs an instance of the KeyProvider_SspiClient class. /// </summary> /// <param name="requiredFeatures">SSPI features that will be provided by the security session.</param> /// <param name="packageName">The name of the used SSPI package.</param> /// <param name="authIdentity">The authentication identity used during authentication.</param> /// <param name="targetName">The name of the server which will be the target of the context. See description of the InitializeSecurityContext function in Platform SDK Security.</param> public KeyProvider_SspiClient(SspiFeatureFlags requiredFeatures, SupportedSspiPackages packageName, NetworkCredential authIdentity, string targetName) : this(requiredFeatures, packageName, authIdentity, targetName, null) { }
/// <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; }