// // Only processing SEC_I_RENEGOTIATE. // private int ProcessReadErrorCode(SecurityStatusPal status, byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest, byte[] extraBuffer) { ProtocolToken message = new ProtocolToken(null, status); if (GlobalLog.IsEnabled) { GlobalLog.Print("SecureChannel#" + LoggingHash.HashString(this) + "::***Processing an error Status = " + message.Status.ToString()); } if (message.Renegotiate) { _sslState.ReplyOnReAuthentication(extraBuffer); // Loop on read. return(-1); } if (message.CloseConnection) { _sslState.FinishRead(null); if (asyncRequest != null) { asyncRequest.CompleteUser((object)0); } return(0); } throw new IOException(SR.net_io_decrypt, message.GetException()); }
internal static SecurityStatusPal InitializeSecurityContext( ref SafeFreeCredentials credentialsHandle, ref SafeDeleteContext?securityContext, string?spn, ContextFlagsPal requestedContextFlags, ReadOnlySpan <byte> incomingBlob, ChannelBinding?channelBinding, ref byte[]?resultBlob, out int resultBlobLength, ref ContextFlagsPal contextFlags) { SafeFreeNegoCredentials negoCredentialsHandle = (SafeFreeNegoCredentials)credentialsHandle; if (negoCredentialsHandle.IsDefault && string.IsNullOrEmpty(spn)) { throw new PlatformNotSupportedException(SR.net_nego_not_supported_empty_target_with_defaultcreds); } SecurityStatusPal status = EstablishSecurityContext( negoCredentialsHandle, ref securityContext, channelBinding, spn, requestedContextFlags, incomingBlob, out resultBlob, ref contextFlags); resultBlobLength = resultBlob?.Length ?? 0; return(status); }
// // Only processing SEC_I_RENEGOTIATE. // private int ProcessReadErrorCode(SecurityStatusPal errorCode, byte[] buffer, int offset, int count, byte[] extraBuffer) { // ERROR - examine what kind ProtocolToken message = new ProtocolToken(null, errorCode); if (GlobalLog.IsEnabled) { GlobalLog.Print("SecureChannel#" + LoggingHash.HashString(this) + "::***Processing an error Status = " + message.Status.ToString()); } if (message.Renegotiate) { _SslState.ReplyOnReAuthentication(extraBuffer); // Loop on read. return(-1); } if (message.CloseConnection) { _SslState.FinishRead(null); return(0); } throw new IOException(SR.net_io_decrypt, message.GetException()); }
private int ProcessReadErrorCode(SecurityStatusPal status, byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest, byte[] extraBuffer) { ProtocolToken message = new ProtocolToken(null, status); if (NetEventSource.IsEnabled) { NetEventSource.Info(null, $"***Processing an error Status = {message.Status}"); } if (message.Renegotiate) { _sslState.ReplyOnReAuthentication(extraBuffer); // Loop on read. return(-1); } if (message.CloseConnection) { _sslState.FinishRead(null); asyncRequest?.CompleteUser(0); return(0); } throw new IOException(SR.net_io_decrypt, message.GetException()); }
// // Client side starts here, but server also loops through this method. // private void SendBlob(byte[] incoming, int count) { ProtocolToken message = _context.NextMessage(incoming, 0, count); _securityStatus = message.Status; if (message.Size != 0) { if (_context.IsServer && _CachedSession == CachedSessionStatus.Unknown) { // //[Schannel] If the first call to ASC returns a token less than 200 bytes, // then it's a reconnect (a handshake based on a cache entry). // _CachedSession = message.Size < 200 ? CachedSessionStatus.IsCached : CachedSessionStatus.IsNotCached; } if (_framing == Framing.Unified) { _framing = DetectFraming(message.Payload, message.Payload.Length); } InnerStream.Write(message.Payload, 0, message.Size); } CheckCompletionBeforeNextReceive(message); }
// // readBytes == SSL Data Payload size on input or 0 on EOF. // private int ProcessFrameBody(int readBytes, byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) { if (readBytes == 0) { // EOF throw new IOException(SR.net_io_eof); } // Set readBytes to total number of received bytes. readBytes += SecureChannel.ReadHeaderSize; // Decrypt into internal buffer, change "readBytes" to count now _Decrypted Bytes_. int data_offset = 0; SecurityStatusPal status = _sslState.DecryptData(InternalBuffer, ref data_offset, ref readBytes); if (status.ErrorCode != SecurityStatusPalErrorCode.OK) { byte[] extraBuffer = null; if (readBytes != 0) { extraBuffer = new byte[readBytes]; Buffer.BlockCopy(InternalBuffer, data_offset, extraBuffer, 0, readBytes); } // Reset internal buffer count. SkipBytes(InternalBufferCount); return(ProcessReadErrorCode(status, buffer, offset, count, asyncRequest, extraBuffer)); } if (readBytes == 0 && count != 0) { // Read again since remote side has sent encrypted 0 bytes. SkipBytes(InternalBufferCount); return(-1); } // Decrypted data start from "data_offset" offset, the total count can be shrunk after decryption. EnsureInternalBufferSize(0, data_offset + readBytes); SkipBytes(data_offset); if (readBytes > count) { readBytes = count; } Buffer.BlockCopy(InternalBuffer, InternalOffset, buffer, offset, readBytes); // This will adjust both the remaining internal buffer count and the offset. SkipBytes(readBytes); _sslState.FinishRead(null); if (asyncRequest != null) { asyncRequest.CompleteUser((object)readBytes); } return(readBytes); }
/// <summary> /// Generate SSPI context /// </summary> /// <param name="handle">SNI connection handle</param> /// <param name="receivedBuff">Receive buffer</param> /// <param name="receivedLength">Received length</param> /// <param name="sendBuff">Send buffer</param> /// <param name="sendLength">Send length</param> /// <param name="serverName">Service Principal Name buffer</param> /// <param name="serverNameLength">Length of Service Principal Name</param> /// <returns>SNI error code</returns> public void GenSspiClientContext(SspiClientContextStatus sspiClientContextStatus, byte[] receivedBuff, ref byte[] sendBuff, byte[] serverName) { SafeDeleteContext securityContext = sspiClientContextStatus.SecurityContext; ContextFlagsPal contextFlags = sspiClientContextStatus.ContextFlags; SafeFreeCredentials credentialsHandle = sspiClientContextStatus.CredentialsHandle; SecurityBuffer[] inSecurityBufferArray = null; if (securityContext == null) //first iteration { credentialsHandle = NegotiateStreamPal.AcquireDefaultCredential(Kerberos, false); } else { inSecurityBufferArray = new SecurityBuffer[] { new SecurityBuffer(receivedBuff, SecurityBufferType.SECBUFFER_TOKEN) }; } int tokenSize = NegotiateStreamPal.QueryMaxTokenSize(Kerberos); SecurityBuffer outSecurityBuffer = new SecurityBuffer(tokenSize, SecurityBufferType.SECBUFFER_TOKEN); ContextFlagsPal requestedContextFlags = ContextFlagsPal.Connection | ContextFlagsPal.Confidentiality | ContextFlagsPal.MutualAuth; string serverSPN = System.Text.Encoding.UTF8.GetString(serverName); SecurityStatusPal statusCode = NegotiateStreamPal.InitializeSecurityContext( credentialsHandle, ref securityContext, serverSPN, requestedContextFlags, inSecurityBufferArray, outSecurityBuffer, ref contextFlags); if (statusCode.ErrorCode == SecurityStatusPalErrorCode.CompleteNeeded || statusCode.ErrorCode == SecurityStatusPalErrorCode.CompAndContinue) { inSecurityBufferArray = new SecurityBuffer[] { outSecurityBuffer }; statusCode = NegotiateStreamPal.CompleteAuthToken(ref securityContext, inSecurityBufferArray); } sendBuff = outSecurityBuffer.token; sspiClientContextStatus.SecurityContext = securityContext; sspiClientContextStatus.ContextFlags = contextFlags; sspiClientContextStatus.CredentialsHandle = credentialsHandle; if (IsErrorStatus(statusCode.ErrorCode)) { if (statusCode.ErrorCode == SecurityStatusPalErrorCode.InternalError && statusCode.Exception is Interop.NetSecurityNative.GssApiException) // when unable to access Kerberos Ticket { throw new Exception(SQLMessage.KerberosTicketMissingError() + "\n" + statusCode); } else { throw new Exception(SQLMessage.SSPIGenerateError() + "\n" + statusCode); } } }
/*++ * Encrypt - Encrypts our bytes before we send them over the wire * * PERF: make more efficient, this does an extra copy when the offset * is non-zero. * * Input: * buffer - bytes for sending * offset - * size - * output - Encrypted bytes * --*/ internal SecurityStatusPal Encrypt(byte[] buffer, int offset, int size, ref byte[] output, out int resultSize) { GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::Encrypt"); GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::Encrypt() - offset: " + offset.ToString() + " size: " + size.ToString() + " buffersize: " + buffer.Length.ToString()); GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::Encrypt() buffer:"); GlobalLog.Dump(buffer, Math.Min(buffer.Length, 128)); byte[] writeBuffer; try { if (offset < 0 || offset > (buffer == null ? 0 : buffer.Length)) { throw new ArgumentOutOfRangeException("offset"); } if (size < 0 || size > (buffer == null ? 0 : buffer.Length - offset)) { throw new ArgumentOutOfRangeException("size"); } resultSize = 0; int bufferSizeNeeded = checked (size + _headerSize + _trailerSize); if (output != null && bufferSizeNeeded <= output.Length) { writeBuffer = output; } else { writeBuffer = new byte[bufferSizeNeeded]; } Buffer.BlockCopy(buffer, offset, writeBuffer, _headerSize, size); } catch (Exception e) { if (!ExceptionCheck.IsFatal(e)) { GlobalLog.Assert(false, "SecureChannel#" + Logging.HashString(this) + "::Encrypt", "Arguments out of range."); } throw; } SecurityStatusPal secStatus = SslStreamPal.EncryptMessage(_securityContext, writeBuffer, size, _headerSize, _trailerSize, out resultSize); if (secStatus != SecurityStatusPal.OK) { GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::Encrypt ERROR", secStatus.ToString()); } else { output = writeBuffer; GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::Encrypt OK", "data size:" + resultSize.ToString()); } return(secStatus); }
internal static SecurityStatusPal InitializeSecurityContext( SafeFreeCredentials credentialsHandle, ref SafeDeleteContext securityContext, string[] spns, ContextFlagsPal requestedContextFlags, SecurityBuffer[] inSecurityBufferArray, SecurityBuffer outSecurityBuffer, ref ContextFlagsPal contextFlags) { // TODO (Issue #3718): The second buffer can contain a channel binding which is not supported if ((null != inSecurityBufferArray) && (inSecurityBufferArray.Length > 1)) { throw new PlatformNotSupportedException(Strings.net_nego_channel_binding_not_supported); } SafeFreeNegoCredentials negoCredentialsHandle = (SafeFreeNegoCredentials)credentialsHandle; SecurityStatusPal status = default; foreach (string spn in spns) { if (negoCredentialsHandle.IsDefault && string.IsNullOrEmpty(spn)) { throw new PlatformNotSupportedException(Strings.net_nego_not_supported_empty_target_with_defaultcreds); } status = EstablishSecurityContext( negoCredentialsHandle, ref securityContext, spn, requestedContextFlags, ((inSecurityBufferArray != null && inSecurityBufferArray.Length != 0) ? inSecurityBufferArray[0] : null), outSecurityBuffer, ref contextFlags); if (status.ErrorCode != SecurityStatusPalErrorCode.InternalError) { break; // Successful case, exit the loop with current SPN. } else { securityContext = null; // Reset security context to be generated again for next SPN. } } // Confidentiality flag should not be set if not requested if (status.ErrorCode == SecurityStatusPalErrorCode.CompleteNeeded) { ContextFlagsPal mask = ContextFlagsPal.Confidentiality; if ((requestedContextFlags & mask) != (contextFlags & mask)) { throw new PlatformNotSupportedException(Strings.net_nego_protection_level_not_supported); } } return(status); }
public static SecurityStatusPal DecryptMessage(SafeDeleteContext securityContext, byte[] buffer, ref int offset, ref int count) { SecurityStatusPal retVal = EncryptDecryptHelper(securityContext, buffer, offset, count, false, ref buffer, out int resultSize); if (retVal.ErrorCode == SecurityStatusPalErrorCode.OK || retVal.ErrorCode == SecurityStatusPalErrorCode.Renegotiate) { count = resultSize; } return(retVal); }
private static SecurityStatusPal HandshakeInternal( SafeFreeCredentials credential, ref SafeDeleteContext context, SecurityBuffer inputBuffer, SecurityBuffer outputBuffer, bool isServer, bool remoteCertRequired, string targetName) { Debug.Assert(!credential.IsInvalid); try { SafeDeleteSslContext sslContext = ((SafeDeleteSslContext)context); if ((null == context) || context.IsInvalid) { sslContext = new SafeDeleteSslContext(credential as SafeFreeSslCredentials, isServer); context = sslContext; if (!string.IsNullOrEmpty(targetName)) { Debug.Assert(!isServer, "targetName should not be set for server-side handshakes"); Interop.AppleCrypto.SslSetTargetName(sslContext.SslContext, targetName); } if (remoteCertRequired) { Debug.Assert(isServer, "remoteCertRequired should not be set for client-side handshakes"); Interop.AppleCrypto.SslSetAcceptClientCert(sslContext.SslContext); } } if (inputBuffer != null && inputBuffer.size > 0) { sslContext.Write(inputBuffer.token, inputBuffer.offset, inputBuffer.size); } SecurityStatusPal status = PerformHandshake(sslContext.SslContext); byte[] output = sslContext.ReadPendingWrites(); outputBuffer.offset = 0; outputBuffer.size = output?.Length ?? 0; outputBuffer.token = output; return(status); } catch (Exception exc) { return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, exc)); } }
private static SecurityStatusPal HandshakeInternal( SafeFreeCredentials credential, ref SafeDeleteSslContext?context, ReadOnlySpan <byte> inputBuffer, ref byte[]?outputBuffer, SslAuthenticationOptions sslAuthenticationOptions, SelectClientCertificate?clientCertificateSelectionCallback) { Debug.Assert(!credential.IsInvalid); try { SafeDeleteSslContext?sslContext = ((SafeDeleteSslContext?)context); if ((null == context) || context.IsInvalid) { sslContext = new SafeDeleteSslContext((credential as SafeFreeSslCredentials) !, sslAuthenticationOptions); context = sslContext; } if (inputBuffer.Length > 0) { sslContext !.Write(inputBuffer); } SafeSslHandle sslHandle = sslContext !.SslContext; SecurityStatusPal status = PerformHandshake(sslHandle); if (status.ErrorCode == SecurityStatusPalErrorCode.CredentialsNeeded && clientCertificateSelectionCallback != null) { X509Certificate2?clientCertificate = clientCertificateSelectionCallback(out bool _); if (clientCertificate != null) { sslAuthenticationOptions.CertificateContext = SslStreamCertificateContext.Create(clientCertificate); SafeDeleteSslContext.SetCertificate(sslContext.SslContext, sslAuthenticationOptions.CertificateContext); } // We either got certificate or we can proceed without it. It is up to the server to decide if either is OK. status = PerformHandshake(sslHandle); } outputBuffer = sslContext.ReadPendingWrites(); return(status); } catch (Exception exc) { return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, exc)); } }
private static SecurityStatusPal HandshakeInternal( SafeFreeCredentials credential, ref SafeDeleteSslContext?context, ReadOnlySpan <byte> inputBuffer, ref byte[]?outputBuffer, SslAuthenticationOptions sslAuthenticationOptions) { Debug.Assert(!credential.IsInvalid); try { SafeDeleteSslContext?sslContext = ((SafeDeleteSslContext?)context); if ((null == context) || context.IsInvalid) { sslContext = new SafeDeleteSslContext((credential as SafeFreeSslCredentials) !, sslAuthenticationOptions); context = sslContext; if (!string.IsNullOrEmpty(sslAuthenticationOptions.TargetHost)) { Debug.Assert(!sslAuthenticationOptions.IsServer, "targetName should not be set for server-side handshakes"); Interop.AppleCrypto.SslSetTargetName(sslContext.SslContext, sslAuthenticationOptions.TargetHost); } if (sslAuthenticationOptions.IsServer && sslAuthenticationOptions.RemoteCertRequired) { Interop.AppleCrypto.SslSetAcceptClientCert(sslContext.SslContext); } } if (inputBuffer.Length > 0) { sslContext !.Write(inputBuffer); } SafeSslHandle sslHandle = sslContext !.SslContext; SecurityStatusPal status = PerformHandshake(sslHandle); outputBuffer = sslContext.ReadPendingWrites(); return(status); } catch (Exception exc) { return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, exc)); } }
internal static SecurityStatusPal InitializeSecurityContext( SafeFreeCredentials credentialsHandle, ref SafeDeleteContext securityContext, string spn, ContextFlagsPal requestedContextFlags, SecurityBuffer[] inSecurityBufferArray, SecurityBuffer outSecurityBuffer, ref ContextFlagsPal contextFlags) { SafeFreeNegoCredentials negoCredentialsHandle = (SafeFreeNegoCredentials)credentialsHandle; if (negoCredentialsHandle.IsDefault && string.IsNullOrEmpty(spn)) { throw new PlatformNotSupportedException(SR.net_nego_not_supported_empty_target_with_defaultcreds); } SecurityBuffer cbtBuffer = null; if ((inSecurityBufferArray != null) && (inSecurityBufferArray.Length > 1)) { Debug.Assert(inSecurityBufferArray[1].type == SecurityBufferType.SECBUFFER_CHANNEL_BINDINGS); cbtBuffer = inSecurityBufferArray[1]; } SecurityStatusPal status = EstablishSecurityContext( negoCredentialsHandle, ref securityContext, cbtBuffer, spn, requestedContextFlags, ((inSecurityBufferArray != null && inSecurityBufferArray.Length != 0) ? inSecurityBufferArray[0] : null), outSecurityBuffer, ref contextFlags); // Confidentiality flag should not be set if not requested if (status.ErrorCode == SecurityStatusPalErrorCode.CompleteNeeded) { ContextFlagsPal mask = ContextFlagsPal.Confidentiality; if ((requestedContextFlags & mask) != (contextFlags & mask)) { throw new PlatformNotSupportedException(SR.net_nego_protection_level_not_supported); } } return(status); }
// // readBytes == SSL Data Payload size on input or 0 on EOF. // private int ProcessFrameBody(int readBytes, byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) { if (readBytes == 0) { // EOF throw new IOException(SR.net_io_eof); } // At this point, readBytes contains the size of the header plus body. // Set _decrytpedBytesOffset/Count to the current frame we have (including header) // DecryptData will decrypt in-place and modify these to point to the actual decrypted data, which may be smaller. _decryptedBytesOffset = _internalOffset; _decryptedBytesCount = readBytes; SecurityStatusPal status = _sslState.DecryptData(_internalBuffer, ref _decryptedBytesOffset, ref _decryptedBytesCount); // Treat the bytes we just decrypted as consumed // Note, we won't do another buffer read until the decrypted bytes are processed ConsumeBufferedBytes(readBytes); if (status.ErrorCode != SecurityStatusPalErrorCode.OK) { byte[] extraBuffer = null; if (_decryptedBytesCount != 0) { extraBuffer = new byte[_decryptedBytesCount]; Buffer.BlockCopy(_internalBuffer, _decryptedBytesOffset, extraBuffer, 0, _decryptedBytesCount); _decryptedBytesCount = 0; } return(ProcessReadErrorCode(status, asyncRequest, extraBuffer)); } if (_decryptedBytesCount == 0) { // Read again since remote side has sent encrypted 0 bytes. return(-1); } int copyBytes = CopyDecryptedData(buffer, offset, count); _sslState.FinishRead(null); asyncRequest?.CompleteUser(copyBytes); return(copyBytes); }
// internal ProtocolToken NextMessage(byte[] incoming, int offset, int count) { GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::NextMessage"); byte[] nextmsg = null; SecurityStatusPal errorCode = GenerateToken(incoming, offset, count, ref nextmsg); if (!_serverMode && errorCode == SecurityStatusPal.CredentialsNeeded) { GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::NextMessage() returned SecurityStatusPal.CredentialsNeeded"); SetRefreshCredentialNeeded(); errorCode = GenerateToken(incoming, offset, count, ref nextmsg); } ProtocolToken token = new ProtocolToken(nextmsg, errorCode); GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::NextMessage", token.ToString()); return(token); }
internal SecurityStatusPal Decrypt(byte[] payload, ref int offset, ref int count) { GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::Decrypt() - offset: " + offset.ToString() + " size: " + count.ToString() + " buffersize: " + payload.Length.ToString()); if (offset < 0 || offset > (payload == null ? 0 : payload.Length)) { GlobalLog.Assert(false, "SecureChannel#" + Logging.HashString(this) + "::Encrypt", "Argument 'offset' out of range."); throw new ArgumentOutOfRangeException("offset"); } if (count < 0 || count > (payload == null ? 0 : payload.Length - offset)) { GlobalLog.Assert(false, "SecureChannel#" + Logging.HashString(this) + "::Encrypt", "Argument 'count' out of range."); throw new ArgumentOutOfRangeException("count"); } SecurityStatusPal secStatus = SslStreamPal.DecryptMessage(_securityContext, payload, ref offset, ref count); return(secStatus); }
public static SecurityStatusPal DecryptMessage(SafeDeleteSslContext securityContext, byte[] buffer, ref int offset, ref int count) { try { int resultSize = Interop.OpenSsl.Decrypt(securityContext.SslContext, new Span <byte>(buffer, offset, count), out Interop.Ssl.SslErrorCode errorCode); SecurityStatusPal retVal = MapNativeErrorCode(errorCode); if (retVal.ErrorCode == SecurityStatusPalErrorCode.OK || retVal.ErrorCode == SecurityStatusPalErrorCode.Renegotiate) { count = resultSize; } return(retVal); } catch (Exception ex) { return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, ex)); } }
internal static SecurityStatusPal InitializeSecurityContext( ref SafeFreeCredentials credentialsHandle, ref SafeDeleteContext?securityContext, string?spn, ContextFlagsPal requestedContextFlags, byte[]?incomingBlob, ChannelBinding?channelBinding, ref byte[]?resultBlob, ref ContextFlagsPal contextFlags) { SafeFreeNegoCredentials negoCredentialsHandle = (SafeFreeNegoCredentials)credentialsHandle; if (negoCredentialsHandle.IsDefault && string.IsNullOrEmpty(spn)) { throw new PlatformNotSupportedException(SR.net_nego_not_supported_empty_target_with_defaultcreds); } SecurityStatusPal status = EstablishSecurityContext( negoCredentialsHandle, ref securityContext, channelBinding, spn, requestedContextFlags, incomingBlob, ref resultBlob, ref contextFlags); // Confidentiality flag should not be set if not requested if (status.ErrorCode == SecurityStatusPalErrorCode.CompleteNeeded) { ContextFlagsPal mask = ContextFlagsPal.Confidentiality; if ((requestedContextFlags & mask) != (contextFlags & mask)) { throw new PlatformNotSupportedException(SR.net_nego_protection_level_not_supported); } } return(status); }
public static Exception GetException(SecurityStatusPal status) { return status.Exception ?? new Interop.OpenSsl.SslException((int)status.ErrorCode); }
// // Client side starts here, but server also loops through this method. // private void StartSendBlob(byte[] incoming, int count, AsyncProtocolRequest asyncRequest) { ProtocolToken message = Context.NextMessage(incoming, 0, count); _securityStatus = message.Status; if (message.Size != 0) { if (Context.IsServer && _CachedSession == CachedSessionStatus.Unknown) { // //[Schannel] If the first call to ASC returns a token less than 200 bytes, // then it's a reconnect (a handshake based on a cache entry). // _CachedSession = message.Size < 200 ? CachedSessionStatus.IsCached : CachedSessionStatus.IsNotCached; } if (_Framing == Framing.Unified) { _Framing = DetectFraming(message.Payload, message.Payload.Length); } if (asyncRequest == null) { InnerStream.Write(message.Payload, 0, message.Size); } else { asyncRequest.AsyncState = message; IAsyncResult ar = InnerStreamAPM.BeginWrite(message.Payload, 0, message.Size, s_writeCallback, asyncRequest); if (!ar.CompletedSynchronously) { #if DEBUG asyncRequest._DebugAsyncChain = ar; #endif return; } InnerStreamAPM.EndWrite(ar); } } CheckCompletionBeforeNextReceive(message, asyncRequest); }
/// <summary> /// Generate SSPI context /// </summary> /// <param name="sspiClientContextStatus">SSPI client context status</param> /// <param name="receivedBuff">Receive buffer</param> /// <param name="sendBuff">Send buffer</param> /// <param name="serverName">Service Principal Name buffer</param> public void GenSspiClientContext(SspiClientContextStatus sspiClientContextStatus, byte[] receivedBuff, ref byte[] sendBuff, byte[] serverName) { SafeDeleteContext securityContext = sspiClientContextStatus.SecurityContext; ContextFlagsPal contextFlags = sspiClientContextStatus.ContextFlags; SafeFreeCredentials credentialsHandle = sspiClientContextStatus.CredentialsHandle; string securityPackage = NegotiationInfoClass.Negotiate; if (securityContext == null) { credentialsHandle = NegotiateStreamPal.AcquireDefaultCredential(securityPackage, false); } int tokenSize = NegotiateStreamPal.QueryMaxTokenSize(securityPackage); byte[] resultToken = new byte[tokenSize]; ContextFlagsPal requestedContextFlags = ContextFlagsPal.Connection | ContextFlagsPal.Confidentiality | ContextFlagsPal.Delegate | ContextFlagsPal.MutualAuth; string serverSPN = System.Text.Encoding.UTF8.GetString(serverName); SecurityStatusPal statusCode = NegotiateStreamPal.InitializeSecurityContext( ref credentialsHandle, ref securityContext, serverSPN, requestedContextFlags, receivedBuff, null, ref resultToken, ref contextFlags); if (statusCode.ErrorCode == SecurityStatusPalErrorCode.CompleteNeeded || statusCode.ErrorCode == SecurityStatusPalErrorCode.CompAndContinue) { statusCode = NegotiateStreamPal.CompleteAuthToken(ref securityContext, resultToken); resultToken = null; } sendBuff = resultToken; if (sendBuff == null) { sendBuff = Array.Empty <byte>(); } sspiClientContextStatus.SecurityContext = securityContext; sspiClientContextStatus.ContextFlags = contextFlags; sspiClientContextStatus.CredentialsHandle = credentialsHandle; if (IsErrorStatus(statusCode.ErrorCode)) { // Could not access Kerberos Ticket. // // SecurityStatusPalErrorCode.InternalError only occurs in Unix and always comes with a GssApiException, // so we don't need to check for a GssApiException here. if (statusCode.ErrorCode == SecurityStatusPalErrorCode.InternalError) { throw new InvalidOperationException(SQLMessage.KerberosTicketMissingError() + "\n" + statusCode); } else { throw new InvalidOperationException(SQLMessage.SSPIGenerateError() + "\n" + statusCode); } } }
public static Exception GetException(SecurityStatusPal status) { int win32Code = (int)SecurityStatusAdapterPal.GetInteropFromSecurityStatusPal(status); return new Win32Exception(win32Code); }
private void StartWriting(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) { if (asyncRequest != null) { asyncRequest.SetNextRequest(buffer, offset, count, s_resumeAsyncWriteCallback); } // We loop to this method from the callback. // If the last chunk was just completed from async callback (count < 0), we complete user request. if (count >= 0) { byte[] outBuffer = null; if (_pinnableOutputBufferInUse == null) { if (_pinnableOutputBuffer == null) { _pinnableOutputBuffer = s_PinnableWriteBufferCache.AllocateBuffer(); } _pinnableOutputBufferInUse = buffer; outBuffer = _pinnableOutputBuffer; if (PinnableBufferCacheEventSource.Log.IsEnabled()) { PinnableBufferCacheEventSource.Log.DebugMessage3("In System.Net._SslStream.StartWriting Trying Pinnable", this.GetHashCode(), count, PinnableBufferCacheEventSource.AddressOfByteArray(outBuffer)); } } else { if (PinnableBufferCacheEventSource.Log.IsEnabled()) { PinnableBufferCacheEventSource.Log.DebugMessage2("In System.Net._SslStream.StartWriting BufferInUse", this.GetHashCode(), count); } } do { if (count == 0 && !SslStreamPal.CanEncryptEmptyMessage) { // If it's an empty message and the PAL doesn't support that, // we're done. break; } // Request a write IO slot. if (_sslState.CheckEnqueueWrite(asyncRequest)) { // Operation is async and has been queued, return. return; } int chunkBytes = Math.Min(count, _sslState.MaxDataSize); int encryptedBytes; SecurityStatusPal status = _sslState.EncryptData(buffer, offset, chunkBytes, ref outBuffer, out encryptedBytes); if (status.ErrorCode != SecurityStatusPalErrorCode.OK) { // Re-handshake status is not supported. ProtocolToken message = new ProtocolToken(null, status); throw new IOException(SR.net_io_encrypt, message.GetException()); } if (PinnableBufferCacheEventSource.Log.IsEnabled()) { PinnableBufferCacheEventSource.Log.DebugMessage3("In System.Net._SslStream.StartWriting Got Encrypted Buffer", this.GetHashCode(), encryptedBytes, PinnableBufferCacheEventSource.AddressOfByteArray(outBuffer)); } if (asyncRequest != null) { // Prepare for the next request. asyncRequest.SetNextRequest(buffer, offset + chunkBytes, count - chunkBytes, s_resumeAsyncWriteCallback); Task t = _sslState.InnerStream.WriteAsync(outBuffer, 0, encryptedBytes); if (t.IsCompleted) { t.GetAwaiter().GetResult(); } else { IAsyncResult ar = TaskToApm.Begin(t, s_writeCallback, asyncRequest); if (!ar.CompletedSynchronously) { return; } TaskToApm.End(ar); } } else { _sslState.InnerStream.Write(outBuffer, 0, encryptedBytes); } offset += chunkBytes; count -= chunkBytes; // Release write IO slot. _sslState.FinishWrite(); } while (count != 0); } if (asyncRequest != null) { asyncRequest.CompleteUser(); } if (buffer == _pinnableOutputBufferInUse) { _pinnableOutputBufferInUse = null; if (PinnableBufferCacheEventSource.Log.IsEnabled()) { PinnableBufferCacheEventSource.Log.DebugMessage1("In System.Net._SslStream.StartWriting Freeing buffer.", this.GetHashCode()); } } }
internal ProtocolToken(byte[] data, SecurityStatusPal errorCode) { Status = errorCode; Payload = data; Size = data != null ? data.Length : 0; }
private int ProcessReadErrorCode(SecurityStatusPal status, byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest, byte[] extraBuffer) { ProtocolToken message = new ProtocolToken(null, status); if (NetEventSource.IsEnabled) NetEventSource.Info(null, $"***Processing an error Status = {message.Status}"); if (message.Renegotiate) { _sslState.ReplyOnReAuthentication(extraBuffer); // Loop on read. return -1; } if (message.CloseConnection) { _sslState.FinishRead(null); if (asyncRequest != null) { asyncRequest.CompleteUser((object)0); } return 0; } throw new IOException(SR.net_io_decrypt, message.GetException()); }
// This will initiate renegotiation or PHA for Tls1.3 private async Task RenegotiateAsync <TIOAdapter>(CancellationToken cancellationToken) where TIOAdapter : IReadWriteAdapter { if (Interlocked.Exchange(ref _nestedAuth, 1) == 1) { throw new InvalidOperationException(SR.Format(SR.net_io_invalidnestedcall, "authenticate")); } if (Interlocked.Exchange(ref _nestedRead, 1) == 1) { throw new NotSupportedException(SR.Format(SR.net_io_invalidnestedcall, "read")); } if (Interlocked.Exchange(ref _nestedWrite, 1) == 1) { _nestedRead = 0; throw new NotSupportedException(SR.Format(SR.net_io_invalidnestedcall, "write")); } try { if (_buffer.ActiveLength > 0) { throw new InvalidOperationException(SR.net_ssl_renegotiate_buffer); } _sslAuthenticationOptions !.RemoteCertRequired = true; _isRenego = true; SecurityStatusPal status = Renegotiate(out byte[]? nextmsg); if (nextmsg is { Length : > 0 }) { await TIOAdapter.WriteAsync(InnerStream, nextmsg, 0, nextmsg.Length, cancellationToken).ConfigureAwait(false); await TIOAdapter.FlushAsync(InnerStream, cancellationToken).ConfigureAwait(false); } if (status.ErrorCode != SecurityStatusPalErrorCode.OK) { if (status.ErrorCode == SecurityStatusPalErrorCode.NoRenegotiation) { // Peer does not want to renegotiate. That should keep session usable. return; } throw SslStreamPal.GetException(status); } _buffer.EnsureAvailableSpace(InitialHandshakeBufferSize); ProtocolToken message; do { message = await ReceiveBlobAsync <TIOAdapter>(cancellationToken).ConfigureAwait(false); if (message.Size > 0) { await TIOAdapter.WriteAsync(InnerStream, message.Payload !, 0, message.Size, cancellationToken).ConfigureAwait(false); await TIOAdapter.FlushAsync(InnerStream, cancellationToken).ConfigureAwait(false); } }while (message.Status.ErrorCode == SecurityStatusPalErrorCode.ContinueNeeded); CompleteHandshake(_sslAuthenticationOptions !); }
private Task WriteSingleChunk <TWriteAdapter>(TWriteAdapter writeAdapter, ReadOnlyMemory <byte> buffer) where TWriteAdapter : struct, ISslWriteAdapter { // Request a write IO slot. Task ioSlot = writeAdapter.LockAsync(); if (!ioSlot.IsCompletedSuccessfully) { // Operation is async and has been queued, return. return(WaitForWriteIOSlot(writeAdapter, ioSlot, buffer)); } byte[] rentedBuffer = ArrayPool <byte> .Shared.Rent(buffer.Length + FrameOverhead); byte[] outBuffer = rentedBuffer; SecurityStatusPal status = _sslState.EncryptData(buffer, ref outBuffer, out int encryptedBytes); if (status.ErrorCode != SecurityStatusPalErrorCode.OK) { // Re-handshake status is not supported. ArrayPool <byte> .Shared.Return(rentedBuffer); ProtocolToken message = new ProtocolToken(null, status); return(Task.FromException(new IOException(SR.net_io_encrypt, message.GetException()))); } Task t = writeAdapter.WriteAsync(outBuffer, 0, encryptedBytes); if (t.IsCompletedSuccessfully) { ArrayPool <byte> .Shared.Return(rentedBuffer); _sslState.FinishWrite(); return(t); } else { return(CompleteAsync(t, rentedBuffer)); } async Task WaitForWriteIOSlot(TWriteAdapter wAdapter, Task lockTask, ReadOnlyMemory <byte> buff) { await lockTask.ConfigureAwait(false); await WriteSingleChunk(wAdapter, buff).ConfigureAwait(false); } async Task CompleteAsync(Task writeTask, byte[] bufferToReturn) { try { await writeTask.ConfigureAwait(false); } finally { ArrayPool <byte> .Shared.Return(bufferToReturn); _sslState.FinishWrite(); } } }
public static Exception GetException(SecurityStatusPal status) { int win32Code = (int)SecurityStatusAdapterPal.GetInteropFromSecurityStatusPal(status); return(new Win32Exception(win32Code)); }
private async ValueTask <int> ReadAsyncInternal <TReadAdapter>(TReadAdapter adapter, Memory <byte> buffer) where TReadAdapter : ISslReadAdapter { if (Interlocked.Exchange(ref _nestedRead, 1) == 1) { throw new NotSupportedException(SR.Format(SR.net_io_invalidnestedcall, nameof(ReadAsync), "read")); } while (true) { int copyBytes; if (_decryptedBytesCount != 0) { copyBytes = CopyDecryptedData(buffer); _sslState.FinishRead(null); _nestedRead = 0; return(copyBytes); } copyBytes = await adapter.LockAsync(buffer).ConfigureAwait(false); try { if (copyBytes > 0) { return(copyBytes); } ResetReadBuffer(); int readBytes = await FillBufferAsync(adapter, SecureChannel.ReadHeaderSize).ConfigureAwait(false); if (readBytes == 0) { return(0); } int payloadBytes = _sslState.GetRemainingFrameSize(_internalBuffer, _internalOffset, readBytes); if (payloadBytes < 0) { throw new IOException(SR.net_frame_read_size); } readBytes = await FillBufferAsync(adapter, SecureChannel.ReadHeaderSize + payloadBytes).ConfigureAwait(false); if (readBytes < 0) { throw new IOException(SR.net_frame_read_size); } // At this point, readBytes contains the size of the header plus body. // Set _decrytpedBytesOffset/Count to the current frame we have (including header) // DecryptData will decrypt in-place and modify these to point to the actual decrypted data, which may be smaller. _decryptedBytesOffset = _internalOffset; _decryptedBytesCount = readBytes; SecurityStatusPal status = _sslState.DecryptData(_internalBuffer, ref _decryptedBytesOffset, ref _decryptedBytesCount); // Treat the bytes we just decrypted as consumed // Note, we won't do another buffer read until the decrypted bytes are processed ConsumeBufferedBytes(readBytes); if (status.ErrorCode != SecurityStatusPalErrorCode.OK) { byte[] extraBuffer = null; if (_decryptedBytesCount != 0) { extraBuffer = new byte[_decryptedBytesCount]; Buffer.BlockCopy(_internalBuffer, _decryptedBytesOffset, extraBuffer, 0, _decryptedBytesCount); _decryptedBytesCount = 0; } ProtocolToken message = new ProtocolToken(null, status); if (NetEventSource.IsEnabled) { NetEventSource.Info(null, $"***Processing an error Status = {message.Status}"); } if (message.Renegotiate) { if (!_sslState._sslAuthenticationOptions.AllowRenegotiation) { throw new IOException(SR.net_ssl_io_renego); } _sslState.ReplyOnReAuthentication(extraBuffer); // Loop on read. return(-1); } if (message.CloseConnection) { _sslState.FinishRead(null); return(0); } throw new IOException(SR.net_io_decrypt, message.GetException()); } } catch (Exception e) { _sslState.FinishRead(null); if (e is IOException) { throw; } throw new IOException(SR.net_io_read, e); } finally { _nestedRead = 0; } } }
internal static bool IsError(SecurityStatusPal status) { return ((int)status.ErrorCode >= (int)SecurityStatusPalErrorCode.OutOfMemory); }
internal ProtocolToken(byte[] data, SecurityStatusPal status) { Status = status; Payload = data; Size = data != null ? data.Length : 0; }
internal static Win32Exception CreateExceptionFromError(SecurityStatusPal statusCode) { return new Win32Exception(NTE_FAIL, statusCode.ToString()); }
internal static Win32Exception CreateExceptionFromError(SecurityStatusPal statusCode) { return new Win32Exception(NTE_FAIL, (statusCode.Exception != null) ? statusCode.Exception.Message : statusCode.ErrorCode.ToString()); }
public static Exception GetException(SecurityStatusPal status) { return(status.Exception ?? new Win32Exception((int)status.ErrorCode)); }
internal static bool IsError(SecurityStatusPal status) { return((int)status.ErrorCode >= (int)SecurityStatusPalErrorCode.OutOfMemory); }
public static Exception GetException(SecurityStatusPal status) { return(status.Exception ?? new Interop.AndroidCrypto.SslException((int)status.ErrorCode)); }
internal static Win32Exception CreateExceptionFromError(SecurityStatusPal statusCode) { return(new Win32Exception((int)SecurityStatusAdapterPal.GetInteropFromSecurityStatusPal(statusCode))); }
internal static Win32Exception CreateExceptionFromError(SecurityStatusPal statusCode) { return new Win32Exception((int)SecurityStatusAdapterPal.GetInteropFromSecurityStatusPal(statusCode)); }
// // Only processing SEC_I_RENEGOTIATE. // private int ProcessReadErrorCode(SecurityStatusPal status, byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest, byte[] extraBuffer) { ProtocolToken message = new ProtocolToken(null, status); if (GlobalLog.IsEnabled) { GlobalLog.Print("SecureChannel#" + LoggingHash.HashString(this) + "::***Processing an error Status = " + message.Status.ToString()); } if (message.Renegotiate) { _sslState.ReplyOnReAuthentication(extraBuffer); // Loop on read. return -1; } if (message.CloseConnection) { _sslState.FinishRead(null); if (asyncRequest != null) { asyncRequest.CompleteUser((object)0); } return 0; } throw new IOException(SR.net_io_decrypt, message.GetException()); }
internal static Win32Exception CreateExceptionFromError(SecurityStatusPal statusCode) { return(new Win32Exception(NTE_FAIL, (statusCode.Exception != null) ? statusCode.Exception.Message : statusCode.ErrorCode.ToString())); }
// // Only processing SEC_I_RENEGOTIATE. // private int ProcessReadErrorCode(SecurityStatusPal errorCode, byte[] buffer, int offset, int count, byte[] extraBuffer) { // ERROR - examine what kind ProtocolToken message = new ProtocolToken(null, errorCode); GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::***Processing an error Status = " + message.Status.ToString()); if (message.Renegotiate) { _SslState.ReplyOnReAuthentication(extraBuffer); // Loop on read. return -1; } if (message.CloseConnection) { _SslState.FinishRead(null); return 0; } throw new IOException(SR.net_io_decrypt, message.GetException()); }