public SslConnectionInfo(SafeSslHandle sslContext) { string protocolVersion = Interop.Ssl.GetProtocolVersion(sslContext); Protocol = (int)MapProtocolVersion(protocolVersion); int dataCipherAlg; int keyExchangeAlg; int dataHashAlg; int dataKeySize; int dataHashKeySize; if (!Interop.Ssl.GetSslConnectionInfo( sslContext, out dataCipherAlg, out keyExchangeAlg, out dataHashAlg, out dataKeySize, out dataHashKeySize)) { throw Interop.OpenSsl.CreateSslException(SR.net_ssl_get_connection_info_failed); } DataCipherAlg = dataCipherAlg; KeyExchangeAlg = keyExchangeAlg; DataHashAlg = dataHashAlg; DataKeySize = dataKeySize; DataHashKeySize = dataHashKeySize; //Openssl does not provide a way to return a exchange key size. //It internally does calculate the key size before generating key to exchange //It is not a constant (Algorthim specific) either that we can hardcode and return. KeyExchKeySize = 0; }
internal static extern bool GetSslConnectionInfo( SafeSslHandle ssl, out int dataCipherAlg, out int keyExchangeAlg, out int dataHashAlg, out int dataKeySize, out int hashKeySize);
internal static SafeSharedX509NameStackHandle SSL_get_client_CA_list(SafeSslHandle ssl) { Interop.Crypto.CheckValidOpenSslHandle(ssl); SafeSharedX509NameStackHandle handle = SSL_get_client_CA_list_private(ssl); if (!handle.IsInvalid) { handle.SetParent(ssl); } return handle; }
protected override void Dispose(bool disposing) { if (disposing) { if (null != _sslContext) { _sslContext.Dispose(); _sslContext = null; } } base.Dispose(disposing); }
internal SslConnectionInfo(SafeSslHandle sslContext) { string protocolVersion = Interop.Ssl.GetProtocolVersion(sslContext); Protocol = (int)MapProtocolVersion(protocolVersion); if (!Interop.Ssl.GetSslConnectionInfo( sslContext, out DataCipherAlg, out KeyExchangeAlg, out DataHashAlg, out DataKeySize)) { throw Interop.OpenSsl.CreateSslException(SR.net_ssl_get_connection_info_failed); } // TODO (Issue #3362) map key sizes }
internal static bool DoSslHandshake(SafeSslHandle context, byte[] recvBuf, int recvOffset, int recvCount, out byte[] sendBuf, out int sendCount) { sendBuf = null; sendCount = 0; if ((recvBuf != null) && (recvCount > 0)) { BioWrite(context.InputBio, recvBuf, recvOffset, recvCount); } libssl.SslErrorCode error; int retVal = libssl.SSL_do_handshake(context); if (retVal != 1) { error = GetSslError(context, retVal); if ((retVal != -1) || (error != libssl.SslErrorCode.SSL_ERROR_WANT_READ)) { throw CreateSslException(context, SR.net_ssl_handshake_failed_error, retVal); } } sendCount = libssl.BIO_ctrl_pending(context.OutputBio); if (sendCount > 0) { sendBuf = new byte[sendCount]; try { sendCount = BioRead(context.OutputBio, sendBuf, sendCount); } finally { if (sendCount <= 0) { sendBuf = null; sendCount = 0; } } } return ((libssl.SSL_state(context) == (int)libssl.SslState.SSL_ST_OK)); }
public SafeDeleteSslContext(SafeFreeSslCredentials credential, bool isServer, bool remoteCertRequired) : base(credential) { Debug.Assert((null != credential) && !credential.IsInvalid, "Invalid credential used in SafeDeleteSslContext"); try { _sslContext = Interop.OpenSsl.AllocateSslContext( credential.Protocols, credential.CertHandle, credential.CertKeyHandle, credential.Policy, isServer, remoteCertRequired); } catch(Exception ex) { Debug.Write("Exception Caught. - " + ex); Dispose(); throw; } }
internal static SafeChannelBindingHandle QueryChannelBinding(SafeSslHandle context, ChannelBindingKind bindingType) { SafeChannelBindingHandle bindingHandle; switch (bindingType) { case ChannelBindingKind.Endpoint: bindingHandle = new SafeChannelBindingHandle(bindingType); QueryEndPointChannelBinding(context, bindingHandle); break; case ChannelBindingKind.Unique: bindingHandle = new SafeChannelBindingHandle(bindingType); QueryUniqueChannelBinding(context, bindingHandle); break; default: // Keeping parity with windows, we should return null in this case. bindingHandle = null; break; } return bindingHandle; }
private static void QueryUniqueChannelBinding(SafeSslHandle context, SafeChannelBindingHandle bindingHandle) { bool sessionReused = Ssl.SslSessionReused(context); int certHashLength = context.IsServer ^ sessionReused ? Ssl.SslGetPeerFinished(context, bindingHandle.CertHashPtr, bindingHandle.Length) : Ssl.SslGetFinished(context, bindingHandle.CertHashPtr, bindingHandle.Length); if (0 == certHashLength) { throw CreateSslException(SR.net_ssl_get_channel_binding_token_failed); } bindingHandle.SetCertHashLength(certHashLength); }
internal static SafeSharedX509StackHandle GetPeerCertificateChain(SafeSslHandle context) { return Ssl.SslGetPeerCertChain(context); }
internal static int Encrypt(SafeSslHandle context, byte[] buffer, int offset, int count, out Ssl.SslErrorCode errorCode) { Debug.Assert(buffer != null); Debug.Assert(offset >= 0); Debug.Assert(count >= 0); Debug.Assert(buffer.Length >= offset + count); errorCode = Ssl.SslErrorCode.SSL_ERROR_NONE; int retVal; unsafe { fixed (byte* fixedBuffer = buffer) { retVal = Ssl.SslWrite(context, fixedBuffer + offset, count); } } if (retVal != count) { Exception innerError; errorCode = GetSslError(context, retVal, out innerError); retVal = 0; switch (errorCode) { // indicate end-of-file case Ssl.SslErrorCode.SSL_ERROR_ZERO_RETURN: case Ssl.SslErrorCode.SSL_ERROR_WANT_READ: break; default: throw new SslException(SR.Format(SR.net_ssl_encrypt_failed, errorCode), innerError); } } else { int capacityNeeded = Crypto.BioCtrlPending(context.OutputBio); Debug.Assert(buffer.Length >= capacityNeeded, "Input buffer of size " + buffer.Length + " bytes is insufficient since encryption needs " + capacityNeeded + " bytes."); retVal = BioRead(context.OutputBio, buffer, capacityNeeded); } return retVal; }
internal static extern bool IsSslStateOK(SafeSslHandle ssl);
internal static extern void SslSetBio(SafeSslHandle ssl, SafeBioHandle rbio, SafeBioHandle wbio);
internal static extern int SslRead(SafeSslHandle ssl, byte[] buf, int num);
internal static extern bool SslAddExtraChainCert(SafeSslHandle ssl, SafeX509Handle x509);
internal static unsafe extern int SslWrite(SafeSslHandle ssl, byte* buf, int num);
private static extern SafeSharedX509NameStackHandle SslGetClientCAList_private(SafeSslHandle ssl);
internal static extern bool IsSslRenegotiatePending(SafeSslHandle ssl);
internal static SafeSharedX509NameStackHandle SslGetClientCAList(SafeSslHandle ssl) { Crypto.CheckValidOpenSslHandle(ssl); SafeSharedX509NameStackHandle handle = SslGetClientCAList_private(ssl); if (!handle.IsInvalid) { handle.SetParent(ssl); } return handle; }
internal static extern int SslDoHandshake(SafeSslHandle ssl);
internal static extern SslErrorCode SslGetError(SafeSslHandle ssl, int ret);
internal static bool DoSslHandshake(SafeSslHandle context, byte[] recvBuf, int recvOffset, int recvCount, out byte[] sendBuf, out int sendCount) { sendBuf = null; sendCount = 0; if ((recvBuf != null) && (recvCount > 0)) { BioWrite(context.InputBio, recvBuf, recvOffset, recvCount); } int retVal = Ssl.SslDoHandshake(context); if (retVal != 1) { Exception innerError; Ssl.SslErrorCode error = GetSslError(context, retVal, out innerError); if ((retVal != -1) || (error != Ssl.SslErrorCode.SSL_ERROR_WANT_READ)) { throw new SslException(SR.Format(SR.net_ssl_handshake_failed_error, error), innerError); } } sendCount = Crypto.BioCtrlPending(context.OutputBio); if (sendCount > 0) { sendBuf = new byte[sendCount]; try { sendCount = BioRead(context.OutputBio, sendBuf, sendCount); } finally { if (sendCount <= 0) { sendBuf = null; sendCount = 0; } } } bool stateOk = Ssl.IsSslStateOK(context); if (stateOk) { context.MarkHandshakeCompleted(); } return stateOk; }
internal static extern void SslSetConnectState(SafeSslHandle ssl);
internal static int Decrypt(SafeSslHandle context, byte[] outBuffer, int count, out Ssl.SslErrorCode errorCode) { errorCode = Ssl.SslErrorCode.SSL_ERROR_NONE; int retVal = BioWrite(context.InputBio, outBuffer, 0, count); if (retVal == count) { retVal = Ssl.SslRead(context, outBuffer, outBuffer.Length); if (retVal > 0) { count = retVal; } } if (retVal != count) { Exception innerError; errorCode = GetSslError(context, retVal, out innerError); retVal = 0; switch (errorCode) { // indicate end-of-file case Ssl.SslErrorCode.SSL_ERROR_ZERO_RETURN: break; case Ssl.SslErrorCode.SSL_ERROR_WANT_READ: // update error code to renegotiate if renegotiate is pending, otherwise make it SSL_ERROR_WANT_READ errorCode = Ssl.IsSslRenegotiatePending(context) ? Ssl.SslErrorCode.SSL_ERROR_RENEGOTIATE : Ssl.SslErrorCode.SSL_ERROR_WANT_READ; break; default: throw new SslException(SR.Format(SR.net_ssl_decrypt_failed, errorCode), innerError); } } return retVal; }
internal static extern void SslSetAcceptState(SafeSslHandle ssl);
internal static SafeX509Handle GetPeerCertificate(SafeSslHandle context) { return Ssl.SslGetPeerCertificate(context); }
private static extern IntPtr SslGetVersion(SafeSslHandle ssl);
private static void QueryEndPointChannelBinding(SafeSslHandle context, SafeChannelBindingHandle bindingHandle) { using (SafeX509Handle certSafeHandle = GetPeerCertificate(context)) { if (certSafeHandle == null || certSafeHandle.IsInvalid) { throw CreateSslException(SR.net_ssl_invalid_certificate); } bool gotReference = false; try { certSafeHandle.DangerousAddRef(ref gotReference); using (X509Certificate2 cert = new X509Certificate2(certSafeHandle.DangerousGetHandle())) using (HashAlgorithm hashAlgo = GetHashForChannelBinding(cert)) { byte[] bindingHash = hashAlgo.ComputeHash(cert.RawData); bindingHandle.SetCertHash(bindingHash); } } finally { if (gotReference) { certSafeHandle.DangerousRelease(); } } } }
internal static string GetProtocolVersion(SafeSslHandle ssl) { return Marshal.PtrToStringAnsi(SslGetVersion(ssl)); }
private static Ssl.SslErrorCode GetSslError(SafeSslHandle context, int result, out Exception innerError) { ErrorInfo lastErrno = Sys.GetLastErrorInfo(); // cache it before we make more P/Invoke calls, just in case we need it Ssl.SslErrorCode retVal = Ssl.SslGetError(context, result); switch (retVal) { case Ssl.SslErrorCode.SSL_ERROR_SYSCALL: // Some I/O error occurred innerError = Crypto.ErrPeekError() != 0 ? Crypto.CreateOpenSslCryptographicException() : // crypto error queue not empty result == 0 ? new EndOfStreamException() : // end of file that violates protocol result == -1 && lastErrno.Error != Error.SUCCESS ? new IOException(lastErrno.GetErrorMessage(), lastErrno.RawErrno) : // underlying I/O error null; // no additional info available break; case Ssl.SslErrorCode.SSL_ERROR_SSL: // OpenSSL failure occurred. The error queue contains more details. innerError = Interop.Crypto.CreateOpenSslCryptographicException(); break; default: // No additional info available. innerError = null; break; } return retVal; }
public static SafeSslHandle Create(SafeSslContextHandle context, bool isServer) { SafeBioHandle readBio = Interop.Crypto.CreateMemoryBio(); if (readBio.IsInvalid) { return(new SafeSslHandle()); } SafeBioHandle writeBio = Interop.Crypto.CreateMemoryBio(); if (writeBio.IsInvalid) { readBio.Dispose(); return(new SafeSslHandle()); } SafeSslHandle handle = Interop.Ssl.SslCreate(context); if (handle.IsInvalid) { readBio.Dispose(); writeBio.Dispose(); return(handle); } handle._isServer = isServer; // After SSL_set_bio, the BIO handles are owned by SSL pointer // and are automatically freed by SSL_free. To prevent a double // free, we need to keep the ref counts bumped up till SSL_free bool gotRef = false; readBio.DangerousAddRef(ref gotRef); try { bool ignore = false; writeBio.DangerousAddRef(ref ignore); } catch { if (gotRef) { readBio.DangerousRelease(); } throw; } Interop.Ssl.SslSetBio(handle, readBio, writeBio); handle._readBio = readBio; handle._writeBio = writeBio; if (isServer) { Interop.Ssl.SslSetAcceptState(handle); } else { Interop.Ssl.SslSetConnectState(handle); } return(handle); }