runtime: OpenSslCryptographicException: error:03000098:digital envelope routines::invalid digest on CentOS Stream 9
Description
While building .NET 6 using .NET 6 in in CentOS Stream 9 (aka RHEL 9 in-development), I am running into error : Unhandled exception. Interop+Crypto+OpenSslCryptographicException: error:03000098:digital envelope routines::invalid digest
error : Unhandled exception. Interop+Crypto+OpenSslCryptographicException: error:03000098:digital envelope routines::invalid digest
error : at Interop.Crypto.RsaSignHash(SafeEvpPKeyHandle pkey, RSASignaturePaddingMode paddingMode, IntPtr digestAlgorithm, ReadOnlySpan`1 hash, Span`1 destination)
error : at System.Security.Cryptography.RSAImplementation.RSAOpenSsl.TrySignHash(ReadOnlySpan`1 hash, Span`1 destination, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding, Boolean allocateSignature, Int32& bytesWritten, Byte[]& signature)
error : at System.Security.Cryptography.RSAImplementation.RSAOpenSsl.SignHash(Byte[] hash, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding)
error : at Microsoft.CodeAnalysis.SigningUtilities.CalculateRsaSignature(IEnumerable`1 content, RSAParameters privateKey)
error : at Microsoft.CodeAnalysis.DesktopStrongNameProvider.<>c__DisplayClass12_0.<SignBuilder>b__0(IEnumerable`1 content)
error : at System.Reflection.PortableExecutable.PEBuilder.Sign(BlobBuilder peImage, Blob strongNameSignatureFixup, Func`2 signatureProvider)
error : at System.Reflection.PortableExecutable.ManagedPEBuilder.Sign(BlobBuilder peImage, Func`2 signatureProvider)
error : at Microsoft.CodeAnalysis.DesktopStrongNameProvider.SignBuilder(ExtendedPEBuilder peBuilder, BlobBuilder peBlob, RSAParameters privateKey)
error : at Microsoft.Cci.PeWriter.WritePeToStream(EmitContext context, CommonMessageProvider messageProvider, Func`1 getPeStream, Func`1 getPortablePdbStreamOpt, PdbWriter nativePdbWriterOpt, String pdbPathOpt, Boolean metadataOnly, Boolean isDeterministic, Boolean emitTestCoverageData, Nullable`1 privateKeyOpt, CancellationToken cancellationToken)
error : at Microsoft.CodeAnalysis.Compilation.SerializePeToStream(CommonPEModuleBuilder moduleBeingBuilt, DiagnosticBag metadataDiagnostics, CommonMessageProvider messageProvider, Func`1 getPeStream, Func`1 getMetadataPeStreamOpt, Func`1 getPortablePdbStreamOpt, PdbWriter nativePdbWriterOpt, String pdbPathOpt, RebuildData rebuildData, Boolean metadataOnly, Boolean includePrivateMembers, Boolean isDeterministic, Boolean emitTestCoverageData, Nullable`1 privateKeyOpt, CancellationToken cancellationToken)
error : at Microsoft.CodeAnalysis.Compilation.SerializeToPeStream(CommonPEModuleBuilder moduleBeingBuilt, EmitStreamProvider peStreamProvider, EmitStreamProvider metadataPEStreamProvider, EmitStreamProvider pdbStreamProvider, RebuildData rebuildData, Func`2 testSymWriterFactory, DiagnosticBag diagnostics, EmitOptions emitOptions, Nullable`1 privateKeyOpt, CancellationToken cancellationToken)
error : at Microsoft.CodeAnalysis.CommonCompiler.CompileAndEmit(TouchedFileLogger touchedFilesLogger, Compilation& compilation, ImmutableArray`1 analyzers, ImmutableArray`1 generators, ImmutableArray`1 additionalTextFiles, AnalyzerConfigSet analyzerConfigSet, ImmutableArray`1 sourceFileAnalyzerConfigOptions, ImmutableArray`1 embeddedTexts, DiagnosticBag diagnostics, CancellationToken cancellationToken, CancellationTokenSource& analyzerCts, Boolean& reportAnalyzer, AnalyzerDriver& analyzerDriver)
error : at Microsoft.CodeAnalysis.CommonCompiler.RunCore(TextWriter consoleOutput, ErrorLogger errorLogger, CancellationToken cancellationToken)
error : at Microsoft.CodeAnalysis.CommonCompiler.Run(TextWriter consoleOutput, CancellationToken cancellationToken)
error : at Microsoft.CodeAnalysis.CSharp.CommandLine.Csc.<>c__DisplayClass1_0.<Run>b__0(TextWriter tw)
error : at Microsoft.CodeAnalysis.CommandLine.ConsoleUtil.RunWithUtf8Output[T](Boolean utf8Output, TextWriter textWriter, Func`2 func)
error : at Microsoft.CodeAnalysis.CSharp.CommandLine.Csc.Run(String[] args, BuildPaths buildPaths, TextWriter textWriter, IAnalyzerAssemblyLoader analyzerLoader)
error : at Microsoft.CodeAnalysis.CommandLine.BuildClient.RunCompilation(IEnumerable`1 originalArguments, BuildPaths buildPaths, TextWriter textWriter, String pipeName)
error : at Microsoft.CodeAnalysis.CommandLine.BuildClient.Run(IEnumerable`1 arguments, RequestLanguage language, CompileFunc compileFunc, CompileOnServerFunc compileOnServerFunc)
error : at Microsoft.CodeAnalysis.CSharp.CommandLine.Program.MainCore(String[] args)
Full log is here: https://centos.softwarefactory-project.io/zuul/t/centos/build/b00c0fe1895c4e1487350108a41214da
Could this be caused by Disable SHA1 signature creation and verification by default?
Reproduction Steps
It seems like building runtime in a CentOS Stream 9 container should be enough to trigger the bug. Will test and update this step later.
Expected behavior
I can build .NET itself.
Actual behavior
I can’t build .NET, because the compiler needs signing (via OpenSSL) to work.
Regression?
It’s a regression somewhere. Most likely it’s not .NET itself that’s to blame, because this same source code (no changes) built a few days ago.
Known Workarounds
I am testing if an export OPENSSL_ENABLE_SHA1_SIGNATURES=1
will work around the issue.
Edit: Confirmed. It does make the build move past this particular error.
Configuration
- .NET 6 source-build using the 6.0.102 tag of dotnet/installer
- CentOS Stream 9 on x86_64
Other information
No response
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 52 (52 by maintainers)
I will make an attempt but time box it. If it turns out to be more work than expected I may need to defer (my time spent in this repo is purely voluntary).
@tmds @omajid one other thing I wanted to call out about the SHA1 signature disabling in RHEL9 and .NET is how this interacts with TLS.
Currently, this trivial .NET program will fail in RHEL9.
I suspect this is because .NET validates signatures on self-signed in trust stores, whereas OpenSSL does not normally do this. OpenSSL does support this with
-check_ss_sig
. You can reproduce this with the command line:This will connect, but the trace will indicate the same error:
I don’t know if this is a “problem” or not, but since .NET opts in to this strictness check whereas OpenSSL doesn’t normally do this, you might see additional reports about .NET Failing to connect to HTTPS endpoints where the root certificate is RSA-SHA1 signed.
@vcsjones I assume you didn’t find time for this. I’ll give it a shot next week.
That breaks .NET on RHEL9. If the system considers the certificate secure, .NET shouldn’t reject it for Windows-compatibilty sake.
@bartonjs can we drop this strict mode? It causes .NET to reject certificates on RHEL9 which are accepted by system tools like
curl
andwget
.They do not appear to, no. We explicitly enable it here:
https://github.com/dotnet/runtime/blob/424a09cb81c678fb1ba1c27211b80aba2de070ad/src/native/libs/System.Security.Cryptography.Native/pal_x509.c#L277
I think the reason why this was added is because this is what Windows does. Windows checks the signature on self-signed certificates. So this was done so that X509 chain building is more consistent across platforms, as I understand it.
@bartonjs may want to weigh in on this one when he returns.
@tmds @omajid I can get the tests to fail in CentOS 9 Stream. Here is a Docker file which does so.
This was done with the base image sha256:c498ab29be98c552440487f06e78ba22b3892f4b29d37aa208fe7ded95280f17. Note: this hard-codes some paths to assume ARM64. If you are running this docker image on x64, you will need to adjust some paths in the
CMD
.I think this probably means somewhere in your build / test infrastructure, SHA1 is being enabled.
Note that with SHA1 signatures disabled, quite a number of things do not actually work. I can’t even get it to build without enabling SHA1 signatures in a few places.
I get the following test results:
An example failure:
I’m not sure where/what we’d document.
From the RSA perspective, it only applies when on Fedora/CentOS/RHEL when using RSAOpenSsl or RSA.Create() (a custom RSA implementation, such as RSAKeyVault, wouldn’t necessarily have the problem), and at best we’d just link to the RedHat crypto docs for it. (From an API perspective, it’s covered under the blanket docs of “if something goes wrong: CryptographicException”… and this is just “the underlying provider doesn’t support the hash algorithm”. I think RSACryptoServiceProvider -might- still support RSA+MD4, but RSAOpenSsl doesn’t).
From the assembly strong name perspective, we already recommend public sign for .NET Core projects, and don’t know where in that doc stream anyone would find “if building for .NET Framework or .NET Standard (for .NET Framework) from [a RedHat-influenced distro], things get complicated”.
So, I’m not opposed to documentation, just can’t think of where it’d go and how to explain the problem or solution in an approachable manner 😄.
For what it’s worth, this breaks any .NET project that uses strong name signing, not just building .NET itself.
To reproduce, create a new C# project. Add this somewhere:
Grab a strong name key. You can use
testkey.snk
in this repository. Put it next to the csproj.It will fail to build with the same error.