You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
On Linux with OpenSSL 1.1.1, SslStream.NegotiateClientCertificateAsync on a TLS 1.3 connection whose client didn't offer post-handshake authentication throws OpenSslCryptographicException (error:14268117:SSL routines:SSL_verify_client_post_handshake:extension not received). With OpenSSL 3 the same call returns and RemoteCertificate stays null, as #128942 intended.
In Interop.OpenSsl.SslRenegotiate, #128942 recognizes the case by masking the exception's HResult with 0X7FFFFF, at Interop.OpenSsl.cs:696-701:
SecurityStatusPalErrorCodepalErrorCode=(ex?.HResult&0X7FFFFF)switch{279/*SSL_R_EXTENSION_NOT_RECEIVED*/ or
339/*SSL_R_NO_RENEGOTIATION*/=>SecurityStatusPalErrorCode.NoRenegotiation,
_ =>SecurityStatusPalErrorCode.InternalError};
0X7FFFFF is OpenSSL 3's ERR_REASON_MASK: there the code is lib << 23 | reason, 0x0A000117 for this error. OpenSSL 1.1 packs lib << 24 | func << 12 | reason, so the same error is 0x14268117, which masks to 0x268117, and the call falls through to InternalError.
Reproduction Steps
A console app from dotnet new console -n repro (.NET 11 SDK), with this Program.cs:
usingSystem;usingSystem.Net;usingSystem.Net.Security;usingSystem.Net.Sockets;usingSystem.Security.Authentication;usingSystem.Security.Cryptography;usingSystem.Security.Cryptography.X509Certificates;[assembly:System.Runtime.Versioning.SupportedOSPlatform("linux")]Console.WriteLine($"OpenSSL 0x{SafeEvpPKeyHandle.OpenSslVersion:X}");usingRSAkey=RSA.Create(2048);CertificateRequestrequest=new("CN=localhost",key,HashAlgorithmName.SHA256,RSASignaturePadding.Pkcs1);usingX509Certificate2ephemeral=request.CreateSelfSigned(DateTimeOffset.UtcNow.AddDays(-1),DateTimeOffset.UtcNow.AddDays(1));usingX509Certificate2serverCert=X509CertificateLoader.LoadPkcs12(ephemeral.Export(X509ContentType.Pfx),null);usingTcpListenerlistener=new(IPAddress.Loopback,0);listener.Start();usingTcpClienttcpClient=new();Taskconnect=tcpClient.ConnectAsync(IPAddress.Loopback,((IPEndPoint)listener.LocalEndpoint).Port);usingTcpClienttcpServer=awaitlistener.AcceptTcpClientAsync();awaitconnect;usingSslStreamclient=new(tcpClient.GetStream());usingSslStreamserver=new(tcpServer.GetStream());// The client sets no certificate, so it doesn't offer TLS 1.3 post-handshake authentication.awaitTask.WhenAll(client.AuthenticateAsClientAsync(newSslClientAuthenticationOptions{TargetHost="localhost",EnabledSslProtocols=SslProtocols.Tls13,RemoteCertificateValidationCallback=delegate{returntrue;},}),server.AuthenticateAsServerAsync(newSslServerAuthenticationOptions{ServerCertificate=serverCert}));Console.WriteLine($"Negotiated {server.SslProtocol}");// Exchange data so the TLS 1.3 handshake is complete on both sides.byte[]buffer=newbyte[1];awaitclient.WriteAsync(newbyte[]{1});awaitserver.ReadExactlyAsync(buffer);awaitserver.WriteAsync(newbyte[]{2});awaitclient.ReadExactlyAsync(buffer);// The client must be reading for the server's request to be processed.ValueTask<int>clientRead=client.ReadAsync(buffer);try{awaitserver.NegotiateClientCertificateAsync();Console.WriteLine($"NegotiateClientCertificateAsync returned; RemoteCertificate is {(server.RemoteCertificateisnull?"null":"set")}");}catch(Exceptione){Console.WriteLine($"NegotiateClientCertificateAsync threw {e.GetType()}: {e.Message}");}awaitserver.WriteAsync(newbyte[]{3});awaitclientRead;Console.WriteLine("Stream still usable");
Run it where .NET loads OpenSSL 1.1.1. On Ubuntu 22.04 x64 (OpenSSL 3.0.2), Ubuntu 20.04's libssl1.1 unpacked beside the system library does it, from the repro directory:
OpenSSL 0x30000020
Negotiated Tls13
NegotiateClientCertificateAsync returned; RemoteCertificate is null
Stream still usable
Actual behavior
With OpenSSL 1.1.1f:
OpenSSL 0x1010106F
Negotiated Tls13
NegotiateClientCertificateAsync threw Interop+Crypto+OpenSslCryptographicException: error:14268117:SSL routines:SSL_verify_client_post_handshake:extension not received
Stream still usable
Regression?
No. On .NET 10.0.12 the same repro (retargeted to net10.0) throws Interop+OpenSsl+SslException: Operation failed with error - 0. with both OpenSSL 3.0.2 and 1.1.1f. #128942 made the call return on .NET 11, but its check recognizes only OpenSSL 3's error layout.
Known Workarounds
The stream stays usable after the exception, so a server can catch CryptographicException around the call and treat it as "no certificate", at the cost of treating any other OpenSSL failure of the call the same way.
Configuration
.NET 11.0.0-rc.1.26425.128, Ubuntu 22.04 x64 (WSL2), OpenSSL 1.1.1f loaded as above; OpenSSL 3.0.2 on the same machine is not affected. RHEL 8 is on .NET 11's supported OS list, and its derivative Rocky Linux 8 ships openssl-libs 1.1.1k.
Other information
SslStream_NegotiateClientCertificateAsync_Tls13PhaNotOffered, the test #128942 added, fails on OpenSSL 1.1.1f with the same exception.
TlsSession.RequestClientCertificate on a socket-bound session goes through the same check: in the same scenario it returns Complete with OpenSSL 3.0.2 and throws AuthenticationException with OpenSSL 1.1.1f, the exception above as its inner exception.
I have a fix that decodes the reason with the layout of the loaded OpenSSL, only for errors from the SSL library, with a unit test for both layouts and a test for the TlsSession case, and I'll send it as a PR. Could this be assigned to me?
Searching issues and PRs for Tls13PhaNotOffered, 14268117 and "extension not received" found no existing report.
Note
AI-generated, written at my direction and reviewed by me before posting. The repro was compiled and run as written on .NET 11.0.0-rc.1.26425.128 and, retargeted to net10.0, on .NET 10.0.12, on Ubuntu 22.04 x64 with OpenSSL 3.0.2 and 1.1.1f. The test results come from a local Release build of main at 99f3a67, which is also where the excerpts are from. The error-code layouts come from the OpenSSL 1.1.1t and 3.0.2 headers.
Description
On Linux with OpenSSL 1.1.1,
SslStream.NegotiateClientCertificateAsyncon a TLS 1.3 connection whose client didn't offer post-handshake authentication throwsOpenSslCryptographicException(error:14268117:SSL routines:SSL_verify_client_post_handshake:extension not received). With OpenSSL 3 the same call returns andRemoteCertificatestays null, as #128942 intended.In
Interop.OpenSsl.SslRenegotiate, #128942 recognizes the case by masking the exception'sHResultwith0X7FFFFF, atInterop.OpenSsl.cs:696-701:The
HResultis the packed OpenSSL error code,Interop.ERR.cs:111-115:0X7FFFFFis OpenSSL 3'sERR_REASON_MASK: there the code islib << 23 | reason,0x0A000117for this error. OpenSSL 1.1 packslib << 24 | func << 12 | reason, so the same error is0x14268117, which masks to0x268117, and the call falls through toInternalError.Reproduction Steps
A console app from
dotnet new console -n repro(.NET 11 SDK), with thisProgram.cs:Run it where .NET loads OpenSSL 1.1.1. On Ubuntu 22.04 x64 (OpenSSL 3.0.2), Ubuntu 20.04's
libssl1.1unpacked beside the system library does it, from thereprodirectory:curl -O http://archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1f-1ubuntu2_amd64.deb dpkg-deb -x libssl1.1_1.1.1f-1ubuntu2_amd64.deb ssl111 dotnet build -c Release DOTNET_OPENSSL_VERSION_OVERRIDE=1.1 LD_LIBRARY_PATH=$PWD/ssl111/usr/lib/x86_64-linux-gnu dotnet bin/Release/net11.0/repro.dllExpected behavior
The call returns, as it does with OpenSSL 3.0.2:
Actual behavior
With OpenSSL 1.1.1f:
Regression?
No. On .NET 10.0.12 the same repro (retargeted to
net10.0) throwsInterop+OpenSsl+SslException: Operation failed with error - 0.with both OpenSSL 3.0.2 and 1.1.1f. #128942 made the call return on .NET 11, but its check recognizes only OpenSSL 3's error layout.Known Workarounds
The stream stays usable after the exception, so a server can catch
CryptographicExceptionaround the call and treat it as "no certificate", at the cost of treating any other OpenSSL failure of the call the same way.Configuration
.NET 11.0.0-rc.1.26425.128, Ubuntu 22.04 x64 (WSL2), OpenSSL 1.1.1f loaded as above; OpenSSL 3.0.2 on the same machine is not affected. RHEL 8 is on .NET 11's supported OS list, and its derivative Rocky Linux 8 ships
openssl-libs1.1.1k.Other information
SslStream_NegotiateClientCertificateAsync_Tls13PhaNotOffered, the test #128942 added, fails on OpenSSL 1.1.1f with the same exception.TlsSession.RequestClientCertificateon a socket-bound session goes through the same check: in the same scenario it returnsCompletewith OpenSSL 3.0.2 and throwsAuthenticationExceptionwith OpenSSL 1.1.1f, the exception above as its inner exception.I have a fix that decodes the reason with the layout of the loaded OpenSSL, only for errors from the SSL library, with a unit test for both layouts and a test for the
TlsSessioncase, and I'll send it as a PR. Could this be assigned to me?Searching issues and PRs for
Tls13PhaNotOffered,14268117and "extension not received" found no existing report.Note
AI-generated, written at my direction and reviewed by me before posting. The repro was compiled and run as written on .NET 11.0.0-rc.1.26425.128 and, retargeted to
net10.0, on .NET 10.0.12, on Ubuntu 22.04 x64 with OpenSSL 3.0.2 and 1.1.1f. The test results come from a local Release build ofmainat 99f3a67, which is also where the excerpts are from. The error-code layouts come from the OpenSSL 1.1.1t and 3.0.2 headers.