public static SecurityStatusPal ApplyShutdownToken(ref SafeFreeCredentials credentialsHandle, SafeDeleteContext securityContext) { SafeDeleteSslContext sslContext = ((SafeDeleteSslContext)securityContext); // Unset the quiet shutdown option initially configured. Interop.Ssl.SslSetQuietShutdown(sslContext.SslContext, 0); int status = Interop.Ssl.SslShutdown(sslContext.SslContext); if (status == 0) { // Call SSL_shutdown again for a bi-directional shutdown. status = Interop.Ssl.SslShutdown(sslContext.SslContext); } if (status == 1) { return(new SecurityStatusPal(SecurityStatusPalErrorCode.OK)); } Interop.Ssl.SslErrorCode code = Interop.Ssl.SslGetError(sslContext.SslContext, status); if (code == Interop.Ssl.SslErrorCode.SSL_ERROR_WANT_READ || code == Interop.Ssl.SslErrorCode.SSL_ERROR_WANT_WRITE) { return(new SecurityStatusPal(SecurityStatusPalErrorCode.OK)); } else { return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, new Interop.OpenSsl.SslException((int)code))); } }
public static SecurityStatusPal DecryptMessage( SafeDeleteContext securityContext, byte[] buffer, ref int offset, ref int count) { try { SafeDeleteSslContext sslContext = (SafeDeleteSslContext)securityContext; SafeSslHandle sslHandle = sslContext.SslContext; sslContext.Write(buffer, offset, count); unsafe { fixed(byte *offsetInput = &buffer[offset]) { int written; PAL_TlsIo status; lock (sslHandle) { status = Interop.AppleCrypto.SslRead(sslHandle, offsetInput, count, out written); } if (status < 0) { return(new SecurityStatusPal( SecurityStatusPalErrorCode.InternalError, Interop.AppleCrypto.CreateExceptionForOSStatus((int)status))); } count = written; switch (status) { case PAL_TlsIo.Success: case PAL_TlsIo.WouldBlock: return(new SecurityStatusPal(SecurityStatusPalErrorCode.OK)); case PAL_TlsIo.ClosedGracefully: return(new SecurityStatusPal(SecurityStatusPalErrorCode.ContextExpired)); case PAL_TlsIo.Renegotiate: return(new SecurityStatusPal(SecurityStatusPalErrorCode.Renegotiate)); default: Debug.Fail($"Unknown status value: {status}"); return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError)); } } } } catch (Exception e) { return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, e)); } }
public static SecurityStatusPal AcceptSecurityContext( ref SafeFreeCredentials credential, ref SafeDeleteSslContext context, byte[] inputBuffer, int offset, int count, ref byte[] outputBuffer, SslAuthenticationOptions sslAuthenticationOptions) { return(HandshakeInternal(credential, ref context, new ReadOnlySpan <byte>(inputBuffer, offset, count), ref outputBuffer, sslAuthenticationOptions)); }
public static SecurityStatusPal AcceptSecurityContext( ref SafeFreeCredentials credential, ref SafeDeleteSslContext context, ArraySegment <byte> inputBuffer, ref byte[] outputBuffer, SslAuthenticationOptions sslAuthenticationOptions) { return(HandshakeInternal(credential, ref context, inputBuffer, ref outputBuffer, sslAuthenticationOptions)); }
//------------------------------------------------------------------- internal static unsafe int InitializeSecurityContext( ref SafeFreeCredentials inCredentials, ref SafeDeleteSslContext refContext, string targetName, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, ReadOnlySpan <SecurityBuffer> inSecBuffers, ref SecurityBuffer outSecBuffer, ref Interop.SspiCli.ContextFlags outFlags) { #if TRACE_VERBOSE if (NetEventSource.IsEnabled) { NetEventSource.Enter(null, $"credential:{inCredentials}, crefContext:{refContext}, targetName:{targetName}, inFlags:{inFlags}, endianness:{endianness}"); NetEventSource.Info(null, $"inSecBuffers.Length = {inSecBuffers.Length}"); } #endif if (inCredentials == null) { throw new ArgumentNullException(nameof(inCredentials)); } Interop.SspiCli.SecBufferDesc inSecurityBufferDescriptor = new Interop.SspiCli.SecBufferDesc(inSecBuffers.Length); Interop.SspiCli.SecBufferDesc outSecurityBufferDescriptor = new Interop.SspiCli.SecBufferDesc(1); // Actually, this is returned in outFlags. bool isSspiAllocated = (inFlags & Interop.SspiCli.ContextFlags.AllocateMemory) != 0 ? true : false; int errorCode = -1; bool isContextAbsent = true; if (refContext != null) { isContextAbsent = refContext._handle.IsZero; } // Optional output buffer that may need to be freed. SafeFreeContextBuffer outFreeContextBuffer = null; try { Span <Interop.SspiCli.SecBuffer> inUnmanagedBuffer = stackalloc Interop.SspiCli.SecBuffer[inSecurityBufferDescriptor.cBuffers]; inUnmanagedBuffer.Clear(); fixed(void *inUnmanagedBufferPtr = inUnmanagedBuffer) fixed(void *pinnedToken0 = inSecBuffers.Length > 0 ? inSecBuffers[0].token : null) fixed(void *pinnedToken1 = inSecBuffers.Length > 1 ? inSecBuffers[1].token : null) fixed(void *pinnedToken2 = inSecBuffers.Length > 2 ? inSecBuffers[2].token : null) // pin all buffers, even if null or not used, to avoid needing to allocate GCHandles { Debug.Assert(inSecBuffers.Length <= 3); // Fix Descriptor pointer that points to unmanaged SecurityBuffers. inSecurityBufferDescriptor.pBuffers = inUnmanagedBufferPtr; for (int index = 0; index < inSecurityBufferDescriptor.cBuffers; ++index) { ref readonly SecurityBuffer securityBuffer = ref inSecBuffers[index];
internal static SecurityStatusPal InitializeSecurityContext( ref SafeFreeCredentials credentialsHandle, ref SafeDeleteContext securityContext, string spn, ContextFlagsPal requestedContextFlags, byte[] incomingBlob, ChannelBinding channelBinding, ref byte[] resultBlob, ref ContextFlagsPal contextFlags) { #if netstandard Span <SecurityBuffer> inSecurityBufferSpan = new SecurityBuffer[2]; #else TwoSecurityBuffers twoSecurityBuffers = default; Span <SecurityBuffer> inSecurityBufferSpan = MemoryMarshal.CreateSpan(ref twoSecurityBuffers._item0, 2); #endif int inSecurityBufferSpanLength = 0; if (incomingBlob != null && channelBinding != null) { inSecurityBufferSpan[0] = new SecurityBuffer(incomingBlob, SecurityBufferType.SECBUFFER_TOKEN); inSecurityBufferSpan[1] = new SecurityBuffer(channelBinding); inSecurityBufferSpanLength = 2; } else if (incomingBlob != null) { inSecurityBufferSpan[0] = new SecurityBuffer(incomingBlob, SecurityBufferType.SECBUFFER_TOKEN); inSecurityBufferSpanLength = 1; } else if (channelBinding != null) { inSecurityBufferSpan[0] = new SecurityBuffer(channelBinding); inSecurityBufferSpanLength = 1; } inSecurityBufferSpan = inSecurityBufferSpan.Slice(0, inSecurityBufferSpanLength); var outSecurityBuffer = new SecurityBuffer(resultBlob, SecurityBufferType.SECBUFFER_TOKEN); Interop.SspiCli.ContextFlags outContextFlags = Interop.SspiCli.ContextFlags.Zero; // There is only one SafeDeleteContext type on Windows which is SafeDeleteSslContext so this cast is safe. SafeDeleteSslContext sslContext = (SafeDeleteSslContext)securityContext; Interop.SECURITY_STATUS winStatus = (Interop.SECURITY_STATUS)SSPIWrapper.InitializeSecurityContext( GlobalSSPI.SSPIAuth, ref credentialsHandle, ref sslContext, spn, ContextFlagsAdapterPal.GetInteropFromContextFlagsPal(requestedContextFlags), Interop.SspiCli.Endianness.SECURITY_NETWORK_DREP, inSecurityBufferSpan, ref outSecurityBuffer, ref outContextFlags); securityContext = sslContext; resultBlob = outSecurityBuffer.token; contextFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop(outContextFlags); return(SecurityStatusAdapterPal.GetSecurityStatusPalFromInterop(winStatus)); }
public static SecurityStatusPal InitializeSecurityContext( ref SafeFreeCredentials credential, ref SafeDeleteSslContext context, string targetName, ReadOnlySpan <byte> inputBuffer, ref byte[] outputBuffer, SslAuthenticationOptions sslAuthenticationOptions) { return(HandshakeInternal(credential, ref context, inputBuffer, ref outputBuffer, sslAuthenticationOptions)); }
private static SecurityStatusPal HandshakeInternal( SafeFreeCredentials credential, ref SafeDeleteContext context, SecurityBuffer inputBuffer, SecurityBuffer 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 != null && inputBuffer.size > 0) { sslContext.Write(inputBuffer.token, inputBuffer.offset, inputBuffer.size); } SafeSslHandle sslHandle = sslContext.SslContext; SecurityStatusPal status; lock (sslHandle) { status = PerformHandshake(sslHandle); } 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)); } }
public static SecurityStatusPal DecryptMessage( SafeDeleteSslContext securityContext, Span <byte> buffer, out int offset, out int count) { offset = 0; count = 0; try { SafeSslHandle sslHandle = securityContext.SslContext; securityContext.Write(buffer); unsafe { fixed(byte *ptr = buffer) { PAL_TlsIo status = Interop.AppleCrypto.SslRead(sslHandle, ptr, buffer.Length, out int written); if (status < 0) { return(new SecurityStatusPal( SecurityStatusPalErrorCode.InternalError, Interop.AppleCrypto.CreateExceptionForOSStatus((int)status))); } count = written; offset = 0; switch (status) { case PAL_TlsIo.Success: case PAL_TlsIo.WouldBlock: return(new SecurityStatusPal(SecurityStatusPalErrorCode.OK)); case PAL_TlsIo.ClosedGracefully: return(new SecurityStatusPal(SecurityStatusPalErrorCode.ContextExpired)); case PAL_TlsIo.Renegotiate: return(new SecurityStatusPal(SecurityStatusPalErrorCode.Renegotiate)); default: Debug.Fail($"Unknown status value: {status}"); return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError)); } } } } catch (Exception e) { return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, e)); } }
private static SecurityStatusPal HandshakeInternal(SafeFreeCredentials credential, ref SafeDeleteSslContext context, ArraySegment <byte> inputBuffer, ref byte[] outputBuffer, SslAuthenticationOptions sslAuthenticationOptions) { Debug.Assert(!credential.IsInvalid); byte[] output = null; int outputSize = 0; try { if ((null == context) || context.IsInvalid) { context = new SafeDeleteSslContext(credential as SafeFreeSslCredentials, sslAuthenticationOptions); } bool done; if (inputBuffer.Array == null) { done = Interop.OpenSsl.DoSslHandshake(((SafeDeleteSslContext)context).SslContext, null, 0, 0, out output, out outputSize); } else { done = Interop.OpenSsl.DoSslHandshake(((SafeDeleteSslContext)context).SslContext, inputBuffer.Array, inputBuffer.Offset, inputBuffer.Count, out output, out outputSize); } // When the handshake is done, and the context is server, check if the alpnHandle target was set to null during ALPN. // If it was, then that indicates ALPN failed, send failure. // We have this workaround, as openssl supports terminating handshake only from version 1.1.0, // whereas ALPN is supported from version 1.0.2. SafeSslHandle sslContext = ((SafeDeleteSslContext)context).SslContext; if (done && sslAuthenticationOptions.IsServer && sslAuthenticationOptions.ApplicationProtocols != null && sslContext.AlpnHandle.IsAllocated && sslContext.AlpnHandle.Target == null) { return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, Interop.OpenSsl.CreateSslException(SR.net_alpn_failed))); } outputBuffer = outputSize == 0 ? null : outputSize == output.Length ? output : new Span <byte>(output, 0, outputSize).ToArray(); return(new SecurityStatusPal(done ? SecurityStatusPalErrorCode.OK : SecurityStatusPalErrorCode.ContinueNeeded)); } catch (Exception exc) { // Even if handshake failed we may have Alert to sent. if (outputSize > 0) { outputBuffer = outputSize == output.Length ? output : new Span <byte>(output, 0, outputSize).ToArray(); } return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, exc)); } }
public static SecurityStatusPal DecryptMessage(SafeDeleteSslContext 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); }
public static SecurityStatusPal EncryptMessage(SafeDeleteSslContext securityContext, ReadOnlyMemory <byte> input, int headerSize, int trailerSize, ref byte[] output, out int resultSize) { try { resultSize = Interop.OpenSsl.Encrypt(securityContext.SslContext, input.Span, ref output, out Interop.Ssl.SslErrorCode errorCode); return(MapNativeErrorCode(errorCode)); } catch (Exception ex) { resultSize = 0; return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, ex)); } }
internal static SecurityStatusPal CompleteAuthToken( ref SafeDeleteContext securityContext, byte[] incomingBlob) { // There is only one SafeDeleteContext type on Windows which is SafeDeleteSslContext so this cast is safe. SafeDeleteSslContext sslContext = (SafeDeleteSslContext)securityContext; var inSecurityBuffer = new SecurityBuffer(incomingBlob, SecurityBufferType.SECBUFFER_TOKEN); Interop.SECURITY_STATUS winStatus = (Interop.SECURITY_STATUS)SSPIWrapper.CompleteAuthToken( GlobalSSPI.SSPIAuth, ref sslContext, in inSecurityBuffer); securityContext = sslContext; return(SecurityStatusAdapterPal.GetSecurityStatusPalFromInterop(winStatus)); }
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)); } }
public static SecurityStatusPal ApplyShutdownToken( ref SafeFreeCredentials?credentialsHandle, SafeDeleteSslContext securityContext) { SafeSslHandle sslHandle = securityContext.SslContext; bool success = Interop.AndroidCrypto.SSLStreamShutdown(sslHandle); if (success) { return(new SecurityStatusPal(SecurityStatusPalErrorCode.OK)); } return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError)); }
public static SecurityStatusPal ApplyShutdownToken( ref SafeFreeCredentials credentialsHandle, SafeDeleteContext securityContext) { SafeDeleteSslContext sslContext = ((SafeDeleteSslContext)securityContext); int osStatus = Interop.AppleCrypto.SslShutdown(sslContext.SslContext); if (osStatus == 0) { return(new SecurityStatusPal(SecurityStatusPalErrorCode.OK)); } return(new SecurityStatusPal( SecurityStatusPalErrorCode.InternalError, Interop.AppleCrypto.CreateExceptionForOSStatus(osStatus))); }
private static SecurityStatusPal HandshakeInternal(SafeFreeCredentials credential, ref SafeDeleteContext context, SecurityBuffer inputBuffer, SecurityBuffer outputBuffer, SslAuthenticationOptions sslAuthenticationOptions) { Debug.Assert(!credential.IsInvalid); try { if ((null == context) || context.IsInvalid) { context = new SafeDeleteSslContext(credential as SafeFreeSslCredentials, sslAuthenticationOptions); } byte[] output = null; int outputSize; bool done; if (null == inputBuffer) { done = Interop.OpenSsl.DoSslHandshake(((SafeDeleteSslContext)context).SslContext, null, 0, 0, out output, out outputSize); } else { done = Interop.OpenSsl.DoSslHandshake(((SafeDeleteSslContext)context).SslContext, inputBuffer.token, inputBuffer.offset, inputBuffer.size, out output, out outputSize); } // When the handshake is done, and the context is server, check if the alpnHandle target was set to null during ALPN. // If it was, then that indiciates ALPN failed, send failure. // We have this workaround, as openssl supports terminating handshake only from version 1.1.0, // whereas ALPN is supported from version 1.0.2. SafeSslHandle sslContext = ((SafeDeleteSslContext)context).SslContext; if (done && sslAuthenticationOptions.IsServer && sslAuthenticationOptions.ApplicationProtocols != null && sslContext.AlpnHandle.IsAllocated && sslContext.AlpnHandle.Target == null) { return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, Interop.OpenSsl.CreateSslException(SR.net_alpn_failed))); } outputBuffer.size = outputSize; outputBuffer.offset = 0; outputBuffer.token = outputSize > 0 ? output : null; return(new SecurityStatusPal(done ? SecurityStatusPalErrorCode.OK : SecurityStatusPalErrorCode.ContinueNeeded)); } catch (Exception exc) { return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, exc)); } }
public static SecurityStatusPal EncryptMessage( SafeDeleteContext securityContext, ReadOnlyMemory <byte> input, int headerSize, int trailerSize, ref byte[] output, out int resultSize) { resultSize = 0; Debug.Assert(input.Length > 0, $"{nameof(input.Length)} > 0 since {nameof(CanEncryptEmptyMessage)} is false"); try { SafeDeleteSslContext sslContext = (SafeDeleteSslContext)securityContext; SafeSslHandle sslHandle = sslContext.SslContext; PAL_SSLStreamStatus ret = Interop.AndroidCrypto.SSLStreamWrite(sslHandle, input); SecurityStatusPalErrorCode statusCode = ret switch { PAL_SSLStreamStatus.OK => SecurityStatusPalErrorCode.OK, PAL_SSLStreamStatus.NeedData => SecurityStatusPalErrorCode.ContinueNeeded, PAL_SSLStreamStatus.Renegotiate => SecurityStatusPalErrorCode.Renegotiate, PAL_SSLStreamStatus.Closed => SecurityStatusPalErrorCode.ContextExpired, _ => SecurityStatusPalErrorCode.InternalError }; if (sslContext.BytesReadyForConnection <= output?.Length) { resultSize = sslContext.ReadPendingWrites(output, 0, output.Length); } else { output = sslContext.ReadPendingWrites() !; resultSize = output.Length; } return(new SecurityStatusPal(statusCode)); } catch (Exception e) { return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, e)); } }
internal static SecurityStatusPal InitializeSecurityContext( ref SafeFreeCredentials credentialsHandle, ref SafeDeleteContext securityContext, string spn, ContextFlagsPal requestedContextFlags, byte[] incomingBlob, ChannelBinding channelBinding, ref byte[] resultBlob, ref ContextFlagsPal contextFlags) { InputSecurityBuffers inputBuffers = default; if (incomingBlob != null) { inputBuffers.SetNextBuffer(new InputSecurityBuffer(incomingBlob, SecurityBufferType.SECBUFFER_TOKEN)); } if (channelBinding != null) { inputBuffers.SetNextBuffer(new InputSecurityBuffer(channelBinding)); } var outSecurityBuffer = new SecurityBuffer(resultBlob, SecurityBufferType.SECBUFFER_TOKEN); Interop.SspiCli.ContextFlags outContextFlags = Interop.SspiCli.ContextFlags.Zero; // There is only one SafeDeleteContext type on Windows which is SafeDeleteSslContext so this cast is safe. SafeDeleteSslContext sslContext = (SafeDeleteSslContext)securityContext; Interop.SECURITY_STATUS winStatus = (Interop.SECURITY_STATUS)SSPIWrapper.InitializeSecurityContext( GlobalSSPI.SSPIAuth, ref credentialsHandle, ref sslContext, spn, ContextFlagsAdapterPal.GetInteropFromContextFlagsPal(requestedContextFlags), Interop.SspiCli.Endianness.SECURITY_NETWORK_DREP, inputBuffers, ref outSecurityBuffer, ref outContextFlags); securityContext = sslContext; resultBlob = outSecurityBuffer.token; contextFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop(outContextFlags); return(SecurityStatusAdapterPal.GetSecurityStatusPalFromInterop(winStatus)); }
private static SecurityStatusPal HandshakeInternal( SafeFreeCredentials credential, ref SafeDeleteSslContext?context, ReadOnlySpan <byte> inputBuffer, ref byte[]?outputBuffer, SslAuthenticationOptions sslAuthenticationOptions) { try { SafeDeleteSslContext?sslContext = ((SafeDeleteSslContext?)context); if ((context == null) || context.IsInvalid) { context = new SafeDeleteSslContext(sslAuthenticationOptions); sslContext = context; } if (inputBuffer.Length > 0) { sslContext !.Write(inputBuffer); } SafeSslHandle sslHandle = sslContext !.SslContext; PAL_SSLStreamStatus ret = Interop.AndroidCrypto.SSLStreamHandshake(sslHandle); SecurityStatusPalErrorCode statusCode = ret switch { PAL_SSLStreamStatus.OK => SecurityStatusPalErrorCode.OK, PAL_SSLStreamStatus.NeedData => SecurityStatusPalErrorCode.ContinueNeeded, _ => SecurityStatusPalErrorCode.InternalError }; outputBuffer = sslContext.ReadPendingWrites(); return(new SecurityStatusPal(statusCode)); } catch (Exception exc) { return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, exc)); } }
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)); } }
public static SecurityStatusPal DecryptMessage( SafeDeleteSslContext securityContext, Span <byte> buffer, out int offset, out int count) { offset = 0; count = 0; try { SafeSslHandle sslHandle = securityContext.SslContext; securityContext.Write(buffer); PAL_SSLStreamStatus ret = Interop.AndroidCrypto.SSLStreamRead(sslHandle, buffer, out int read); if (ret == PAL_SSLStreamStatus.Error) { return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError)); } count = read; SecurityStatusPalErrorCode statusCode = ret switch { PAL_SSLStreamStatus.OK => SecurityStatusPalErrorCode.OK, PAL_SSLStreamStatus.NeedData => SecurityStatusPalErrorCode.OK, PAL_SSLStreamStatus.Renegotiate => SecurityStatusPalErrorCode.Renegotiate, PAL_SSLStreamStatus.Closed => SecurityStatusPalErrorCode.ContextExpired, _ => SecurityStatusPalErrorCode.InternalError }; return(new SecurityStatusPal(statusCode)); } catch (Exception e) { return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, e)); } }
public static ChannelBinding?QueryContextChannelBinding(SafeDeleteSslContext securityContext, ChannelBindingKind attribute) { ChannelBinding?bindingHandle; if (attribute == ChannelBindingKind.Endpoint) { bindingHandle = EndpointChannelBindingToken.Build(securityContext); if (bindingHandle == null) { throw Interop.OpenSsl.CreateSslException(SR.net_ssl_invalid_certificate); } } else { bindingHandle = Interop.OpenSsl.QueryChannelBinding( securityContext.SslContext, attribute); } return(bindingHandle); }
private static SecurityStatusPal EncryptDecryptHelper(SafeDeleteSslContext securityContext, ReadOnlyMemory <byte> input, int offset, int size, bool encrypt, ref byte[] output, out int resultSize) { resultSize = 0; try { Interop.Ssl.SslErrorCode errorCode = Interop.Ssl.SslErrorCode.SSL_ERROR_NONE; SafeSslHandle scHandle = securityContext.SslContext; if (encrypt) { resultSize = Interop.OpenSsl.Encrypt(scHandle, input.Span, ref output, out errorCode); } else { resultSize = Interop.OpenSsl.Decrypt(scHandle, output, offset, size, out errorCode); } switch (errorCode) { case Interop.Ssl.SslErrorCode.SSL_ERROR_RENEGOTIATE: return(new SecurityStatusPal(SecurityStatusPalErrorCode.Renegotiate)); case Interop.Ssl.SslErrorCode.SSL_ERROR_ZERO_RETURN: return(new SecurityStatusPal(SecurityStatusPalErrorCode.ContextExpired)); case Interop.Ssl.SslErrorCode.SSL_ERROR_NONE: case Interop.Ssl.SslErrorCode.SSL_ERROR_WANT_READ: return(new SecurityStatusPal(SecurityStatusPalErrorCode.OK)); default: return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, new Interop.OpenSsl.SslException((int)errorCode))); } } catch (Exception ex) { return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, ex)); } }
public static SecurityStatusPal ApplyShutdownToken(ref SafeFreeCredentials credentialsHandle, SafeDeleteContext securityContext) { SafeDeleteSslContext sslContext = ((SafeDeleteSslContext)securityContext); // Unset the quiet shutdown option initially configured. Interop.Ssl.SslSetQuietShutdown(sslContext.SslContext, 0); int status = Interop.Ssl.SslShutdown(sslContext.SslContext); if (status == 0) { // Call SSL_shutdown again for a bi-directional shutdown. status = Interop.Ssl.SslShutdown(sslContext.SslContext); } if (status == 1) { return(new SecurityStatusPal(SecurityStatusPalErrorCode.OK)); } Interop.Ssl.SslErrorCode code = Interop.Ssl.SslGetError(sslContext.SslContext, status); if (code == Interop.Ssl.SslErrorCode.SSL_ERROR_WANT_READ || code == Interop.Ssl.SslErrorCode.SSL_ERROR_WANT_WRITE) { return(new SecurityStatusPal(SecurityStatusPalErrorCode.OK)); } else if (code == Interop.Ssl.SslErrorCode.SSL_ERROR_SSL) { // OpenSSL failure occurred. The error queue contains more details, when building the exception the queue will be cleared. return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, Interop.Crypto.CreateOpenSslCryptographicException())); } else { return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, new Interop.OpenSsl.SslException((int)code))); } }
private static SecurityStatusPal HandshakeInternal(SafeFreeCredentials credential, ref SafeDeleteContext context, SecurityBuffer inputBuffer, SecurityBuffer outputBuffer, SslAuthenticationOptions sslAuthenticationOptions) { Debug.Assert(!credential.IsInvalid); try { if ((null == context) || context.IsInvalid) { context = new SafeDeleteSslContext(credential as SafeFreeSslCredentials, sslAuthenticationOptions); } byte[] output = null; int outputSize; bool done; if (null == inputBuffer) { done = Interop.OpenSsl.DoSslHandshake(((SafeDeleteSslContext)context).SslContext, null, 0, 0, out output, out outputSize); } else { done = Interop.OpenSsl.DoSslHandshake(((SafeDeleteSslContext)context).SslContext, inputBuffer.token, inputBuffer.offset, inputBuffer.size, out output, out outputSize); } outputBuffer.size = outputSize; outputBuffer.offset = 0; outputBuffer.token = outputSize > 0 ? output : null; return(new SecurityStatusPal(done ? SecurityStatusPalErrorCode.OK : SecurityStatusPalErrorCode.ContinueNeeded)); } catch (Exception exc) { return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, exc)); } }
internal static unsafe int AcceptSecurityContext( ref SafeFreeCredentials?inCredentials, ref SafeDeleteSslContext?refContext, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, InputSecurityBuffers inSecBuffers, ref SecurityBuffer outSecBuffer, ref Interop.SspiCli.ContextFlags outFlags) { #if TRACE_VERBOSE if (NetEventSource.IsEnabled) { NetEventSource.Enter(null, $"credential={inCredentials}, refContext={refContext}, inFlags={inFlags}"); NetEventSource.Info(null, $"inSecBuffers.Length = {inSecBuffers.Length}"); } #endif if (inCredentials == null) { throw new ArgumentNullException(nameof(inCredentials)); } Debug.Assert(inSecBuffers.Count <= 3); Interop.SspiCli.SecBufferDesc inSecurityBufferDescriptor = new Interop.SspiCli.SecBufferDesc(inSecBuffers.Count); Interop.SspiCli.SecBufferDesc outSecurityBufferDescriptor = new Interop.SspiCli.SecBufferDesc(count: 2); // Actually, this is returned in outFlags. bool isSspiAllocated = (inFlags & Interop.SspiCli.ContextFlags.AllocateMemory) != 0 ? true : false; int errorCode = -1; bool isContextAbsent = true; if (refContext != null) { isContextAbsent = refContext._handle.IsZero; } // Optional output buffer that may need to be freed. SafeFreeContextBuffer? outFreeContextBuffer = null; Span <Interop.SspiCli.SecBuffer> outUnmanagedBuffer = stackalloc Interop.SspiCli.SecBuffer[2]; outUnmanagedBuffer[1].pvBuffer = IntPtr.Zero; try { // Allocate always maximum to allow better code optimization. Span <Interop.SspiCli.SecBuffer> inUnmanagedBuffer = stackalloc Interop.SspiCli.SecBuffer[3]; fixed(void *inUnmanagedBufferPtr = inUnmanagedBuffer) fixed(void *outUnmanagedBufferPtr = outUnmanagedBuffer) fixed(void *pinnedToken0 = inSecBuffers._item0.Token) fixed(void *pinnedToken1 = inSecBuffers._item1.Token) fixed(void *pinnedToken2 = inSecBuffers._item2.Token) { inSecurityBufferDescriptor.pBuffers = inUnmanagedBufferPtr; // Updated pvBuffer with pinned address. UnmanagedToken takes precedence. if (inSecBuffers.Count > 2) { inUnmanagedBuffer[2].BufferType = inSecBuffers._item2.Type; inUnmanagedBuffer[2].cbBuffer = inSecBuffers._item2.Token.Length; inUnmanagedBuffer[2].pvBuffer = inSecBuffers._item2.UnmanagedToken != null ? (IntPtr)inSecBuffers._item2.UnmanagedToken.DangerousGetHandle() : (IntPtr)pinnedToken2; } if (inSecBuffers.Count > 1) { inUnmanagedBuffer[1].BufferType = inSecBuffers._item1.Type; inUnmanagedBuffer[1].cbBuffer = inSecBuffers._item1.Token.Length; inUnmanagedBuffer[1].pvBuffer = inSecBuffers._item1.UnmanagedToken != null ? (IntPtr)inSecBuffers._item1.UnmanagedToken.DangerousGetHandle() : (IntPtr)pinnedToken1; } if (inSecBuffers.Count > 0) { inUnmanagedBuffer[0].BufferType = inSecBuffers._item0.Type; inUnmanagedBuffer[0].cbBuffer = inSecBuffers._item0.Token.Length; inUnmanagedBuffer[0].pvBuffer = inSecBuffers._item0.UnmanagedToken != null ? (IntPtr)inSecBuffers._item0.UnmanagedToken.DangerousGetHandle() : (IntPtr)pinnedToken0; } fixed(byte *pinnedOutBytes = outSecBuffer.token) { // Fix Descriptor pointer that points to unmanaged SecurityBuffers. outSecurityBufferDescriptor.pBuffers = outUnmanagedBufferPtr; // Copy the SecurityBuffer content into unmanaged place holder. outUnmanagedBuffer[0].cbBuffer = outSecBuffer.size; outUnmanagedBuffer[0].BufferType = outSecBuffer.type; outUnmanagedBuffer[0].pvBuffer = outSecBuffer.token == null || outSecBuffer.token.Length == 0 ? IntPtr.Zero : (IntPtr)(pinnedOutBytes + outSecBuffer.offset); outUnmanagedBuffer[1].cbBuffer = 0; outUnmanagedBuffer[1].BufferType = SecurityBufferType.SECBUFFER_ALERT; if (isSspiAllocated) { outFreeContextBuffer = SafeFreeContextBuffer.CreateEmptyHandle(); } if (refContext == null || refContext.IsInvalid) { // Previous versions unconditionally built a new "refContext" here, but would pass // incorrect arguments to AcceptSecurityContext in cases where an "contextHandle" was // already present and non-zero. if (isContextAbsent) { refContext = new SafeDeleteSslContext(); } } errorCode = MustRunAcceptSecurityContext_SECURITY( ref inCredentials, isContextAbsent, &inSecurityBufferDescriptor, inFlags, endianness, refContext !, ref outSecurityBufferDescriptor, ref outFlags, outFreeContextBuffer); if (NetEventSource.IsEnabled) { NetEventSource.Info(null, "Marshaling OUT buffer"); } // No data written out but there is Alert if (outUnmanagedBuffer[0].cbBuffer == 0 && outUnmanagedBuffer[1].cbBuffer > 0) { outSecBuffer.size = outUnmanagedBuffer[1].cbBuffer; outSecBuffer.type = outUnmanagedBuffer[1].BufferType; outSecBuffer.token = new Span <byte>((byte *)outUnmanagedBuffer[1].pvBuffer, outUnmanagedBuffer[1].cbBuffer).ToArray(); } else { outSecBuffer.size = outUnmanagedBuffer[0].cbBuffer; outSecBuffer.type = outUnmanagedBuffer[0].BufferType; outSecBuffer.token = outUnmanagedBuffer[0].cbBuffer > 0 ? new Span <byte>((byte *)outUnmanagedBuffer[0].pvBuffer, outUnmanagedBuffer[0].cbBuffer).ToArray() : null; } } } } finally { outFreeContextBuffer?.Dispose(); if (outUnmanagedBuffer[1].pvBuffer != IntPtr.Zero) { Interop.SspiCli.FreeContextBuffer(outUnmanagedBuffer[1].pvBuffer); } } if (NetEventSource.IsEnabled) { NetEventSource.Exit(null, $"errorCode:0x{errorCode:x8}, refContext:{refContext}"); } return(errorCode); }
internal static unsafe int InitializeSecurityContext( ref SafeFreeCredentials?inCredentials, ref SafeDeleteSslContext?refContext, string?targetName, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, InputSecurityBuffers inSecBuffers, ref SecurityBuffer outSecBuffer, ref Interop.SspiCli.ContextFlags outFlags) { #if TRACE_VERBOSE if (NetEventSource.IsEnabled) { NetEventSource.Enter(null, $"credential:{inCredentials}, crefContext:{refContext}, targetName:{targetName}, inFlags:{inFlags}, endianness:{endianness}"); NetEventSource.Info(null, $"inSecBuffers.Length = {inSecBuffers.Length}"); } #endif if (inCredentials == null) { throw new ArgumentNullException(nameof(inCredentials)); } Debug.Assert(inSecBuffers.Count <= 3); Interop.SspiCli.SecBufferDesc inSecurityBufferDescriptor = new Interop.SspiCli.SecBufferDesc(inSecBuffers.Count); Interop.SspiCli.SecBufferDesc outSecurityBufferDescriptor = new Interop.SspiCli.SecBufferDesc(1); // Actually, this is returned in outFlags. bool isSspiAllocated = (inFlags & Interop.SspiCli.ContextFlags.AllocateMemory) != 0 ? true : false; int errorCode = -1; bool isContextAbsent = true; if (refContext != null) { isContextAbsent = refContext._handle.IsZero; } // Optional output buffer that may need to be freed. SafeFreeContextBuffer?outFreeContextBuffer = null; try { Span <Interop.SspiCli.SecBuffer> inUnmanagedBuffer = stackalloc Interop.SspiCli.SecBuffer[3]; fixed(void *inUnmanagedBufferPtr = inUnmanagedBuffer) fixed(void *pinnedToken0 = inSecBuffers._item0.Token) fixed(void *pinnedToken1 = inSecBuffers._item1.Token) fixed(void *pinnedToken2 = inSecBuffers._item2.Token) { // Fix Descriptor pointer that points to unmanaged SecurityBuffers. inSecurityBufferDescriptor.pBuffers = inUnmanagedBufferPtr; // Updated pvBuffer with pinned address. UnmanagedToken takes precedence. if (inSecBuffers.Count > 2) { inUnmanagedBuffer[2].BufferType = inSecBuffers._item2.Type; inUnmanagedBuffer[2].cbBuffer = inSecBuffers._item2.Token.Length; inUnmanagedBuffer[2].pvBuffer = inSecBuffers._item2.UnmanagedToken != null ? (IntPtr)inSecBuffers._item2.UnmanagedToken.DangerousGetHandle() : (IntPtr)pinnedToken2; } if (inSecBuffers.Count > 1) { inUnmanagedBuffer[1].BufferType = inSecBuffers._item1.Type; inUnmanagedBuffer[1].cbBuffer = inSecBuffers._item1.Token.Length; inUnmanagedBuffer[1].pvBuffer = inSecBuffers._item1.UnmanagedToken != null ? (IntPtr)inSecBuffers._item1.UnmanagedToken.DangerousGetHandle() : (IntPtr)pinnedToken1; } if (inSecBuffers.Count > 0) { inUnmanagedBuffer[0].BufferType = inSecBuffers._item0.Type; inUnmanagedBuffer[0].cbBuffer = inSecBuffers._item0.Token.Length; inUnmanagedBuffer[0].pvBuffer = inSecBuffers._item0.UnmanagedToken != null ? (IntPtr)inSecBuffers._item0.UnmanagedToken.DangerousGetHandle() : (IntPtr)pinnedToken0; } fixed(byte *pinnedOutBytes = outSecBuffer.token) { // Fix Descriptor pointer that points to unmanaged SecurityBuffers. Interop.SspiCli.SecBuffer outUnmanagedBuffer = default; outSecurityBufferDescriptor.pBuffers = &outUnmanagedBuffer; outUnmanagedBuffer.cbBuffer = outSecBuffer.size; outUnmanagedBuffer.BufferType = outSecBuffer.type; outUnmanagedBuffer.pvBuffer = outSecBuffer.token == null || outSecBuffer.token.Length == 0 ? IntPtr.Zero : (IntPtr)(pinnedOutBytes + outSecBuffer.offset); if (isSspiAllocated) { outFreeContextBuffer = SafeFreeContextBuffer.CreateEmptyHandle(); } if (refContext == null || refContext.IsInvalid) { // Previous versions unconditionally built a new "refContext" here, but would pass // incorrect arguments to InitializeSecurityContextW in cases where an "contextHandle" was // already present and non-zero. if (isContextAbsent) { refContext = new SafeDeleteSslContext(); } } if (targetName == null || targetName.Length == 0) { targetName = dummyStr; } string punyCode = s_idnMapping.GetAscii(targetName); fixed(char *namePtr = punyCode) { errorCode = MustRunInitializeSecurityContext( ref inCredentials, isContextAbsent, (byte *)(((object)targetName == (object)dummyStr) ? null : namePtr), inFlags, endianness, &inSecurityBufferDescriptor, refContext !, ref outSecurityBufferDescriptor, ref outFlags, outFreeContextBuffer); } if (NetEventSource.IsEnabled) { NetEventSource.Info(null, "Marshalling OUT buffer"); } // Get unmanaged buffer with index 0 as the only one passed into PInvoke. outSecBuffer.size = outUnmanagedBuffer.cbBuffer; outSecBuffer.type = outUnmanagedBuffer.BufferType; outSecBuffer.token = outSecBuffer.size > 0 ? new Span <byte>((byte *)outUnmanagedBuffer.pvBuffer, outUnmanagedBuffer.cbBuffer).ToArray() : null; } } } finally { outFreeContextBuffer?.Dispose(); } if (NetEventSource.IsEnabled) { NetEventSource.Exit(null, $"errorCode:0x{errorCode:x8}, refContext:{refContext}"); } return(errorCode); }
private static SecurityStatusPal HandshakeInternal(SafeFreeCredentials credential, ref SafeDeleteContext context, SecurityBuffer inputBuffer, SecurityBuffer outputBuffer, bool isServer, bool remoteCertRequired) { Debug.Assert(!credential.IsInvalid); try { if ((null == context) || context.IsInvalid) { context = new SafeDeleteSslContext(credential as SafeFreeSslCredentials, isServer, remoteCertRequired); } byte[] output = null; int outputSize; bool done; if (null == inputBuffer) { done = Interop.OpenSsl.DoSslHandshake(((SafeDeleteSslContext)context).SslContext, null, 0, 0, out output, out outputSize); } else { done = Interop.OpenSsl.DoSslHandshake(((SafeDeleteSslContext)context).SslContext, inputBuffer.token, inputBuffer.offset, inputBuffer.size, out output, out outputSize); } outputBuffer.size = outputSize; outputBuffer.offset = 0; outputBuffer.token = outputSize > 0 ? output : null; return new SecurityStatusPal(done ? SecurityStatusPalErrorCode.OK : SecurityStatusPalErrorCode.ContinueNeeded); } catch (Exception exc) { return new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, exc); } }
public static void QueryContextConnectionInfo( SafeDeleteSslContext securityContext, ref SslConnectionInfo connectionInfo) { connectionInfo.UpdateSslConnectionInfo(securityContext.SslContext); }
public static SecurityStatusPal EncryptMessage( SafeDeleteContext securityContext, ReadOnlyMemory <byte> input, int headerSize, int trailerSize, ref byte[] output, out int resultSize) { resultSize = 0; Debug.Assert(input.Length > 0, $"{nameof(input.Length)} > 0 since {nameof(CanEncryptEmptyMessage)} is false"); try { SafeDeleteSslContext sslContext = (SafeDeleteSslContext)securityContext; SafeSslHandle sslHandle = sslContext.SslContext; unsafe { MemoryHandle memHandle = input.Retain(pin: true); try { PAL_TlsIo status; lock (sslHandle) { status = Interop.AppleCrypto.SslWrite( sslHandle, (byte *)memHandle.Pointer, input.Length, out int written); } if (status < 0) { return(new SecurityStatusPal( SecurityStatusPalErrorCode.InternalError, Interop.AppleCrypto.CreateExceptionForOSStatus((int)status))); } if (sslContext.BytesReadyForConnection <= output?.Length) { resultSize = sslContext.ReadPendingWrites(output, 0, output.Length); } else { output = sslContext.ReadPendingWrites(); resultSize = output.Length; } switch (status) { case PAL_TlsIo.Success: return(new SecurityStatusPal(SecurityStatusPalErrorCode.OK)); case PAL_TlsIo.WouldBlock: return(new SecurityStatusPal(SecurityStatusPalErrorCode.ContinueNeeded)); default: Debug.Fail($"Unknown status value: {status}"); return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError)); } } finally { memHandle.Dispose(); } } } catch (Exception e) { return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, e)); } }