Cryptography breaking changes for .NET Core 2.1-3.0
The following breaking changes are documented on this page:
.NET Core 3.0
"BEGIN TRUSTED CERTIFICATE" syntax no longer supported for root certificates on Linux
Root certificates on Linux and other Unix-like systems (but not macOS) can be presented in two forms: the standard BEGIN CERTIFICATE
PEM header, and the OpenSSL-specific BEGIN TRUSTED CERTIFICATE
PEM header. The latter syntax allows for additional configuration that has caused compatibility issues with .NET Core's System.Security.Cryptography.X509Certificates.X509Chain class. BEGIN TRUSTED CERTIFICATE
root certificate contents are no longer loaded by the chain engine starting in .NET Core 3.0.
Change description
Previously, both the BEGIN CERTIFICATE
and BEGIN TRUSTED CERTIFICATE
syntaxes were used to populate the root trust list. If the BEGIN TRUSTED CERTIFICATE
syntax was used and additional options were specified in the file, X509Chain may have reported that the chain trust was explicitly disallowed (X509ChainStatusFlags.ExplicitDistrust). However, if the certificate was also specified with the BEGIN CERTIFICATE
syntax in a previously loaded file, the chain trust was allowed.
Starting in .NET Core 3.0, BEGIN TRUSTED CERTIFICATE
contents are no longer read. If the certificate is not also specified via a standard BEGIN CERTIFICATE
syntax, the X509Chain reports that the root is not trusted (X509ChainStatusFlags.UntrustedRoot).
Version introduced
3.0
Recommended action
Most applications are unaffected by this change, but applications that cannot see both root certificate sources because of permissions problems may experience unexpected UntrustedRoot
errors after upgrading.
Many Linux distributions (or distros) write root certificates into two locations: a one-certificate-per-file directory, and a one-file concatenation. On some distros, the one-certificate-per-file directory uses the BEGIN TRUSTED CERTIFICATE
syntax while the file concatenation uses the standard BEGIN CERTIFICATE
syntax. Ensure that any custom root certificates are added as BEGIN CERTIFICATE
in at least one of these locations, and that both locations can be read by your application.
The typical directory is /etc/ssl/certs/ and the typical concatenated file is /etc/ssl/cert.pem. Use the command openssl version -d
to determine the platform-specific root, which may differ from /etc/ssl/. For example, on Ubuntu 18.04, the directory is /usr/lib/ssl/certs/ and the file is /usr/lib/ssl/cert.pem. However, /usr/lib/ssl/certs/ is a symlink to /etc/ssl/certs/ and /usr/lib/ssl/cert.pem does not exist.
$ openssl version -d
OPENSSLDIR: "/usr/lib/ssl"
$ ls -al /usr/lib/ssl
total 12
drwxr-xr-x 3 root root 4096 Dec 12 17:10 .
drwxr-xr-x 73 root root 4096 Feb 20 15:18 ..
lrwxrwxrwx 1 root root 14 Mar 27 2018 certs -> /etc/ssl/certs
drwxr-xr-x 2 root root 4096 Dec 12 17:10 misc
lrwxrwxrwx 1 root root 20 Nov 12 16:58 openssl.cnf -> /etc/ssl/openssl.cnf
lrwxrwxrwx 1 root root 16 Mar 27 2018 private -> /etc/ssl/private
Category
Cryptography
Affected APIs
EnvelopedCms defaults to AES-256 encryption
The default symmetric encryption algorithm used by EnvelopedCms
has changed from TripleDES to AES-256.
Change description
In previous versions, when EnvelopedCms is used to encrypt data without specifying a symmetric encryption algorithm via a constructor overload, the data is encrypted with the TripleDES/3DES/3DEA/DES3-EDE algorithm.
Starting with .NET Core 3.0 (via version 4.6.0 of the System.Security.Cryptography.Pkcs NuGet package), the default algorithm has been changed to AES-256 for algorithm modernization and to improve the security of default options. If a message recipient certificate has a (non-EC) Diffie-Hellman public key, the encryption operation may fail with a CryptographicException due to limitations in the underlying platform.
In the following sample code, the data is encrypted with TripleDES if running on .NET Core 2.2 or earlier. If running on .NET Core 3.0 or later, it's encrypted with AES-256.
EnvelopedCms cms = new EnvelopedCms(content);
cms.Encrypt(recipient);
return cms.Encode();
Version introduced
3.0
Recommended action
If you are negatively impacted by the change, you can restore TripleDES encryption by explicitly specifying the encryption algorithm identifier in an EnvelopedCms constructor that includes a parameter of type AlgorithmIdentifier, such as:
Oid tripleDesOid = new Oid("1.2.840.113549.3.7", null);
AlgorithmIdentifier tripleDesIdentifier = new AlgorithmIdentifier(tripleDesOid);
EnvelopedCms cms = new EnvelopedCms(content, tripleDesIdentifier);
cms.Encrypt(recipient);
return cms.Encode();
Category
Cryptography
Affected APIs
Minimum size for RSAOpenSsl key generation has increased
The minimum size for generating new RSA keys on Linux has increased from 384-bit to 512-bit.
Change description
Starting with .NET Core 3.0, the minimum legal key size reported by the LegalKeySizes
property on RSA instances from RSA.Create, RSAOpenSsl, and RSACryptoServiceProvider on Linux has increased from 384 to 512.
As a result, in .NET Core 2.2 and earlier versions, a method call such as RSA.Create(384)
succeeds. In .NET Core 3.0 and later versions, the method call RSA.Create(384)
throws an exception indicating the size is too small.
This change was made because OpenSSL, which performs the cryptographic operations on Linux, raised its minimum between versions 1.0.2 and 1.1.0. .NET Core 3.0 prefers OpenSSL 1.1.x to 1.0.x, and the minimum reported version was raised to reflect this new higher dependency limitation.
Version introduced
3.0
Recommended action
If you call any of the affected APIs, ensure that the size of any generated keys is not less than the provider minimum.
Note
384-bit RSA is already considered insecure (as is 512-bit RSA). Modern recommendations, such as NIST Special Publication 800-57 Part 1 Revision 4, suggest 2048-bit as the minimum size for newly generated keys.
Category
Cryptography
Affected APIs
.NET Core 3.0 prefers OpenSSL 1.1.x to OpenSSL 1.0.x
.NET Core for Linux, which works across multiple Linux distributions, can support both OpenSSL 1.0.x and OpenSSL 1.1.x. .NET Core 2.1 and .NET Core 2.2 look for 1.0.x first, then fall back to 1.1.x; .NET Core 3.0 looks for 1.1.x first. This change was made to add support for new cryptographic standards.
This change may impact libraries or applications that do platform interop with the OpenSSL-specific interop types in .NET Core.
Change description
In .NET Core 2.2 and earlier versions, the runtime prefers loading OpenSSL 1.0.x over 1.1.x. This means that the IntPtr and SafeHandle types for interop with OpenSSL are used with libcrypto.so.1.0.0 / libcrypto.so.1.0 / libcrypto.so.10 by preference.
Starting with .NET Core 3.0, the runtime prefers loading OpenSSL 1.1.x over OpenSSL 1.0.x, so the IntPtr and SafeHandle types for interop with OpenSSL are used with libcrypto.so.1.1 / libcrypto.so.11 / libcrypto.so.1.1.0 / libcrypto.so.1.1.1 by preference. As a result, libraries and applications that interoperate with OpenSSL directly may have incompatible pointers with the .NET Core-exposed values when upgrading from .NET Core 2.1 or .NET Core 2.2.
Version introduced
3.0
Recommended action
Libraries and applications that do direct operations with OpenSSL need to be careful to ensure they are using the same version of OpenSSL as the .NET Core runtime.
All libraries or applications that use IntPtr or SafeHandle values from the .NET Core cryptographic types directly with OpenSSL should compare the version of the library they use with the new SafeEvpPKeyHandle.OpenSslVersion property to ensure the pointers are compatible.
Category
Cryptography
Affected APIs
- SafeEvpPKeyHandle
- RSAOpenSsl(IntPtr)
- RSAOpenSsl(SafeEvpPKeyHandle)
- RSAOpenSsl.DuplicateKeyHandle()
- DSAOpenSsl(IntPtr)
- DSAOpenSsl(SafeEvpPKeyHandle)
- DSAOpenSsl.DuplicateKeyHandle()
- ECDsaOpenSsl(IntPtr)
- ECDsaOpenSsl(SafeEvpPKeyHandle)
- ECDsaOpenSsl.DuplicateKeyHandle()
- ECDiffieHellmanOpenSsl(IntPtr)
- ECDiffieHellmanOpenSsl(SafeEvpPKeyHandle)
- ECDiffieHellmanOpenSsl.DuplicateKeyHandle()
- X509Certificate.Handle
CryptoStream.Dispose transforms final block only when writing
The CryptoStream.Dispose method, which is used to finish CryptoStream
operations, no longer attempts to transform the final block when reading.
Change description
In previous .NET versions, if a user performed an incomplete read when using CryptoStream in Read mode, the Dispose method could throw an exception (for example, when using AES with padding). The exception was thrown because the final block was attempted to be transformed but the data was incomplete.
In .NET Core 3.0 and later versions, Dispose no longer tries to transform the final block when reading, which allows for incomplete reads.
Reason for change
This change enables incomplete reads from the crypto stream when a network operation is canceled, without the need to catch an exception.
Version introduced
3.0
Recommended action
Most apps should not be affected by this change.
If your application previously caught an exception in case of an incomplete read, you can delete that catch
block.
If your app used transforming of the final block in hashing scenarios, you might need to ensure that the entire stream is read before it's disposed.
Category
Cryptography
Affected APIs
.NET Core 2.1
Boolean parameter of SignedCms.ComputeSignature is respected
In .NET Core, the Boolean silent
parameter of the SignedCms.ComputeSignature(CmsSigner, Boolean) method is respected. A PIN prompt is not shown if this parameter is set to true
.
Change description
In .NET Framework, the silent
parameter of the SignedCms.ComputeSignature(CmsSigner, Boolean) method is ignored, and a PIN prompt is always shown if required by the provider. In .NET Core, the silent
parameter is respected, and if set to true
, a PIN prompt is never shown, even if it's required by the provider.
Support for CMS/PKCS #7 messages was introduced into .NET Core in version 2.1.
Version introduced
2.1
Recommended action
To ensure a PIN prompt appears if required, desktop applications should call SignedCms.ComputeSignature(CmsSigner, Boolean) and set the Boolean parameter to false
. The resulting behavior is the same as on .NET Framework regardless of whether the silent context is disabled there.
Category
Cryptography
Affected APIs
Feedback
https://aka.ms/ContentUserFeedback.
Coming soon: Throughout 2024 we will be phasing out GitHub Issues as the feedback mechanism for content and replacing it with a new feedback system. For more information see:Submit and view feedback for