Repository: dotnet/runtime
File: src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs (C#)

Code before:
            }

            // No common application protocol was negotiated, set the target on the alpnHandle to null.
            // It is ok to clear the handle value here, this results in handshake failure, so the SslStream object is disposed.
            protocolHandle.Target = null;

            return Ssl.SSL_TLSEXT_ERR_ALERT_FATAL;
        }

        [UnmanagedCallersOnly]
        // Invoked from OpenSSL when new session is created.
        // We attached GCHandle to the SSL so we can find back SafeSslContextHandle holding the cache.
        // New session has refCount of 1.
        // If this function returns 0, OpenSSL will drop the refCount and discard the session.
        // If we return 1, the ownership is transferred to us and we will need to call SessionFree().
        private static unsafe int NewSessionCallback(IntPtr ssl, IntPtr session)
        {
            Debug.Assert(ssl != IntPtr.Zero);
            Debug.Assert(session != IntPtr.Zero);

            // Remember if the session used a certificate, this information is used after
            // session resumption. The pointer is not being dereferenced and the refcount
            // is not going to be manipulated.
            IntPtr cert = Interop.Ssl.SslGetCertificate(ssl);

            // Fix for https://github.com/dotnet/runtime/issues/XXXXX
            // In TLS 1.3, new session tickets can be issued on resumed connections.
            // When resuming, no certificate is set on the SSL object, so inherit
            // the cert info from the current (resuming) session.
            if (cert == IntPtr.Zero && Interop.Ssl.SslSessionReused(ssl))
            {
                IntPtr currentSession = Interop.Ssl.SslGetSession(ssl);
                if (currentSession != IntPtr.Zero)
                {
                    cert = Interop.Ssl.SslSessionGetData(currentSession);
                }
            }

            Interop.Ssl.SslSessionSetData(session, cert);

            IntPtr ptr = Ssl.SslGetData(ssl);
            if (ptr != IntPtr.Zero)
            {
                GCHandle gch = GCHandle.FromIntPtr(ptr);
                byte* name = Ssl.SslGetServerName(ssl);
                Debug.Assert(name != null);

                SafeSslContextHandle? ctxHandle = gch.Target as SafeSslContextHandle;
                // There is no relation between SafeSslContextHandle and SafeSslHandle so the handle
                // may be released while the ssl session is still active.
                if (ctxHandle != null && ctxHandle.TryAddSession(name, session))

Review comment (bug):
we don't mention bug numbers in comments like this
```suggestion
```

Code after:
            }

            // No common application protocol was negotiated, set the target on the alpnHandle to null.
            // It is ok to clear the handle value here, this results in handshake failure, so the SslStream object is disposed.
            protocolHandle.Target = null;

            return Ssl.SSL_TLSEXT_ERR_ALERT_FATAL;
        }

        [UnmanagedCallersOnly]
        // Invoked from OpenSSL when new session is created.
        // We attached GCHandle to the SSL so we can find back SafeSslContextHandle holding the cache.
        // New session has refCount of 1.
        // If this function returns 0, OpenSSL will drop the refCount and discard the session.
        // If we return 1, the ownership is transferred to us and we will need to call SessionFree().
        private static unsafe int NewSessionCallback(IntPtr ssl, IntPtr session)
        {
            Debug.Assert(ssl != IntPtr.Zero);
            Debug.Assert(session != IntPtr.Zero);

            // Remember if the session used a certificate, this information is used after
            // session resumption. The pointer is not being dereferenced and the refcount
            // is not going to be manipulated.
            IntPtr cert = Interop.Ssl.SslGetCertificate(ssl);

            // In TLS 1.3, new session tickets can be issued on resumed connections.
            // When resuming, no certificate is set on the SSL object, so inherit
            // the cert info from the current (resuming) session.
            if (cert == IntPtr.Zero && Interop.Ssl.SslSessionReused(ssl))
            {
                IntPtr currentSession = Interop.Ssl.SslGetSession(ssl);
                if (currentSession != IntPtr.Zero)
                {
                    cert = Interop.Ssl.SslSessionGetData(currentSession);
                }
            }

            Interop.Ssl.SslSessionSetData(session, cert);

            IntPtr ptr = Ssl.SslGetData(ssl);
            if (ptr != IntPtr.Zero)
            {
                GCHandle gch = GCHandle.FromIntPtr(ptr);
                byte* name = Ssl.SslGetServerName(ssl);
                Debug.Assert(name != null);

                SafeSslContextHandle? ctxHandle = gch.Target as SafeSslContextHandle;
                // There is no relation between SafeSslContextHandle and SafeSslHandle so the handle
                // may be released while the ssl session is still active.
                if (ctxHandle != null && ctxHandle.TryAddSession(name, session))
                {