diff options
author | Jeremy Barton <jbarton@microsoft.com> | 2021-07-14 04:20:19 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-07-14 04:20:19 +0300 |
commit | f94711de4518163b073734cae2a4d47f5398573c (patch) | |
tree | a7fb8ac9972edb18c2580069a5a9f684941d8e19 /src | |
parent | f6eb259db626d563c15ba340feb6f440d1e1c8ee (diff) |
Finish migrating RSAOpenSsl from RSA* to EVP_PKEY*
This change moves the RSAOpenSsl class (and the RSA.Create() internal class on Linux) to use EVP_PKEY
for the import and export operations, making the interaction with the underlying library based on
PKCS#8 PrivateKeyInfo and X.509 SubjectPublicKeyInfo key blobs.
A large portion of the code is just from splitting the key helpers files to not need all of the encrypted PKCS#8 support
in the System.Security.Cryptography.OpenSsl library, as the encrypted PKCS#8 <-> unencrypted PKCS#8 work provided
by the base classes is sufficient.
Once PKCS#8 and SPKI became the primary modes of interaction the spanified import and export routines for those got
overridden in RSAOpenSsl to avoid SPKI->RSAParameters->SPKI-style conversions.
This change completely eliminates SafeRsaHandle, and the only time that an `RSA*` is used at all is in the legacy RSAOpenSsl(IntPtr) constructor.
Diffstat (limited to 'src')
32 files changed, 1419 insertions, 1077 deletions
diff --git a/src/libraries/Common/src/Internal/Cryptography/Helpers.cs b/src/libraries/Common/src/Internal/Cryptography/Helpers.cs index 6614b3c6d00..b1777c1c1e5 100644 --- a/src/libraries/Common/src/Internal/Cryptography/Helpers.cs +++ b/src/libraries/Common/src/Internal/Cryptography/Helpers.cs @@ -35,7 +35,7 @@ namespace Internal.Cryptography return (mode == CipherMode.CFB ? feedbackSizeInBits : algorithm.BlockSize) / 8; } - internal static bool TryCopyToDestination(ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten) + internal static bool TryCopyToDestination(this ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten) { if (source.TryCopyTo(destination)) { diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs index c8849d343d9..6437c1a7add 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs @@ -12,6 +12,24 @@ internal static partial class Interop internal static partial class Crypto { [DllImport(Libraries.CryptoNative)] + private static extern SafeEvpPKeyHandle CryptoNative_EvpPKeyCreateRsa(IntPtr rsa); + + internal static SafeEvpPKeyHandle EvpPKeyCreateRsa(IntPtr rsa) + { + Debug.Assert(rsa != IntPtr.Zero); + + SafeEvpPKeyHandle pkey = CryptoNative_EvpPKeyCreateRsa(rsa); + + if (pkey.IsInvalid) + { + pkey.Dispose(); + throw CreateOpenSslCryptographicException(); + } + + return pkey; + } + + [DllImport(Libraries.CryptoNative)] private static extern SafeEvpPKeyHandle CryptoNative_RsaGenerateKey(int keySize); internal static SafeEvpPKeyHandle RsaGenerateKey(int keySize) @@ -171,16 +189,5 @@ internal static partial class Interop Debug.Assert(ret == -1); throw CreateOpenSslCryptographicException(); } - - [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpPkeyGetRsa")] - internal static extern SafeRsaHandle EvpPkeyGetRsa(SafeEvpPKeyHandle pkey); - - [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpPkeySetRsa")] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool EvpPkeySetRsa(SafeEvpPKeyHandle pkey, SafeRsaHandle rsa); - - [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpPkeySetRsa")] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool EvpPkeySetRsa(SafeEvpPKeyHandle pkey, IntPtr rsa); } } diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.cs index 8a3fc840b16..924c2da14d4 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Diagnostics; using System.Runtime.InteropServices; using System.Security.Cryptography; @@ -12,6 +13,30 @@ internal static partial class Interop [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpPkeyCreate")] internal static extern SafeEvpPKeyHandle EvpPkeyCreate(); + [DllImport(Libraries.CryptoNative)] + private static extern SafeEvpPKeyHandle CryptoNative_EvpPKeyDuplicate( + SafeEvpPKeyHandle currentKey, + EvpAlgorithmId algorithmId); + + internal static SafeEvpPKeyHandle EvpPKeyDuplicate( + SafeEvpPKeyHandle currentKey, + EvpAlgorithmId algorithmId) + { + Debug.Assert(!currentKey.IsInvalid); + + SafeEvpPKeyHandle pkey = CryptoNative_EvpPKeyDuplicate( + currentKey, + algorithmId); + + if (pkey.IsInvalid) + { + pkey.Dispose(); + throw CreateOpenSslCryptographicException(); + } + + return pkey; + } + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpPkeyDestroy")] internal static extern void EvpPkeyDestroy(IntPtr pkey); @@ -20,5 +45,173 @@ internal static partial class Interop [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_UpRefEvpPkey")] internal static extern int UpRefEvpPkey(SafeEvpPKeyHandle handle); + + [DllImport(Libraries.CryptoNative)] + private static extern unsafe SafeEvpPKeyHandle CryptoNative_DecodeSubjectPublicKeyInfo( + byte* buf, + int len, + int algId); + + [DllImport(Libraries.CryptoNative)] + private static extern unsafe SafeEvpPKeyHandle CryptoNative_DecodePkcs8PrivateKey( + byte* buf, + int len, + int algId); + + internal static unsafe SafeEvpPKeyHandle DecodeSubjectPublicKeyInfo( + ReadOnlySpan<byte> source, + EvpAlgorithmId algorithmId) + { + SafeEvpPKeyHandle handle; + + fixed (byte* sourcePtr = source) + { + handle = CryptoNative_DecodeSubjectPublicKeyInfo( + sourcePtr, + source.Length, + (int)algorithmId); + } + + if (handle.IsInvalid) + { + handle.Dispose(); + throw CreateOpenSslCryptographicException(); + } + + return handle; + } + + internal static unsafe SafeEvpPKeyHandle DecodePkcs8PrivateKey( + ReadOnlySpan<byte> source, + EvpAlgorithmId algorithmId) + { + SafeEvpPKeyHandle handle; + + fixed (byte* sourcePtr = source) + { + handle = CryptoNative_DecodePkcs8PrivateKey( + sourcePtr, + source.Length, + (int)algorithmId); + } + + if (handle.IsInvalid) + { + handle.Dispose(); + throw CreateOpenSslCryptographicException(); + } + + return handle; + } + + [DllImport(Libraries.CryptoNative)] + private static extern int CryptoNative_GetPkcs8PrivateKeySize(IntPtr pkey); + + private static int GetPkcs8PrivateKeySize(IntPtr pkey) + { + int ret = CryptoNative_GetPkcs8PrivateKeySize(pkey); + + if (ret < 0) + { + throw CreateOpenSslCryptographicException(); + } + + return ret; + } + + [DllImport(Libraries.CryptoNative)] + private static extern unsafe int CryptoNative_EncodePkcs8PrivateKey(IntPtr pkey, byte* buf); + + internal static ArraySegment<byte> RentEncodePkcs8PrivateKey(SafeEvpPKeyHandle pkey) + { + bool addedRef = false; + + try + { + pkey.DangerousAddRef(ref addedRef); + IntPtr handle = pkey.DangerousGetHandle(); + + int size = GetPkcs8PrivateKeySize(handle); + byte[] rented = CryptoPool.Rent(size); + int written; + + unsafe + { + fixed (byte* buf = rented) + { + written = CryptoNative_EncodePkcs8PrivateKey(handle, buf); + } + } + + Debug.Assert(written == size); + return new ArraySegment<byte>(rented, 0, written); + } + finally + { + if (addedRef) + { + pkey.DangerousRelease(); + } + } + } + + [DllImport(Libraries.CryptoNative)] + private static extern int CryptoNative_GetSubjectPublicKeyInfoSize(IntPtr pkey); + + private static int GetSubjectPublicKeyInfoSize(IntPtr pkey) + { + int ret = CryptoNative_GetSubjectPublicKeyInfoSize(pkey); + + if (ret < 0) + { + throw CreateOpenSslCryptographicException(); + } + + return ret; + } + + [DllImport(Libraries.CryptoNative)] + private static extern unsafe int CryptoNative_EncodeSubjectPublicKeyInfo(IntPtr pkey, byte* buf); + + internal static ArraySegment<byte> RentEncodeSubjectPublicKeyInfo(SafeEvpPKeyHandle pkey) + { + bool addedRef = false; + + try + { + pkey.DangerousAddRef(ref addedRef); + IntPtr handle = pkey.DangerousGetHandle(); + + int size = GetSubjectPublicKeyInfoSize(handle); + byte[] rented = CryptoPool.Rent(size); + int written; + + unsafe + { + fixed (byte* buf = rented) + { + written = CryptoNative_EncodeSubjectPublicKeyInfo(handle, buf); + } + } + + Debug.Assert(written == size); + return new ArraySegment<byte>(rented, 0, written); + } + finally + { + if (addedRef) + { + pkey.DangerousRelease(); + } + } + } + + internal enum EvpAlgorithmId + { + Unknown = 0, + RSA = 6, + DSA = 116, + ECC = 408, + } } } diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs deleted file mode 100644 index 10525819484..00000000000 --- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs +++ /dev/null @@ -1,136 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; -using System.Security.Cryptography; -using Microsoft.Win32.SafeHandles; - -internal static partial class Interop -{ - internal static partial class Crypto - { - [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_RsaCreate")] - internal static extern SafeRsaHandle RsaCreate(); - - [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_RsaUpRef")] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool RsaUpRef(IntPtr rsa); - - [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_RsaDestroy")] - internal static extern void RsaDestroy(IntPtr rsa); - - internal static SafeRsaHandle DecodeRsaPublicKey(ReadOnlySpan<byte> buf) => - DecodeRsaPublicKey(ref MemoryMarshal.GetReference(buf), buf.Length); - - [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_DecodeRsaPublicKey")] - private static extern SafeRsaHandle DecodeRsaPublicKey(ref byte buf, int len); - - [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_RsaSize")] - internal static extern int RsaSize(SafeRsaHandle rsa); - - internal static RSAParameters ExportRsaParameters(SafeEvpPKeyHandle key, bool includePrivateParameters) - { - using (SafeRsaHandle rsa = EvpPkeyGetRsa(key)) - { - return ExportRsaParameters(rsa, includePrivateParameters); - } - } - - internal static RSAParameters ExportRsaParameters(SafeRsaHandle key, bool includePrivateParameters) - { - Debug.Assert( - key != null && !key.IsInvalid, - "Callers should check the key is invalid and throw an exception with a message"); - - if (key == null || key.IsInvalid) - { - throw new CryptographicException(); - } - - bool addedRef = false; - - try - { - key.DangerousAddRef(ref addedRef); - - IntPtr n, e, d, p, dmp1, q, dmq1, iqmp; - if (!GetRsaParameters(key, out n, out e, out d, out p, out dmp1, out q, out dmq1, out iqmp)) - { - throw new CryptographicException(); - } - - int modulusSize = Crypto.RsaSize(key); - - // RSACryptoServiceProvider expects P, DP, Q, DQ, and InverseQ to all - // be padded up to half the modulus size. - int halfModulus = modulusSize / 2; - - RSAParameters rsaParameters = new RSAParameters - { - Modulus = Crypto.ExtractBignum(n, modulusSize)!, - Exponent = Crypto.ExtractBignum(e, 0)!, - }; - - if (includePrivateParameters) - { - rsaParameters.D = Crypto.ExtractBignum(d, modulusSize); - rsaParameters.P = Crypto.ExtractBignum(p, halfModulus); - rsaParameters.DP = Crypto.ExtractBignum(dmp1, halfModulus); - rsaParameters.Q = Crypto.ExtractBignum(q, halfModulus); - rsaParameters.DQ = Crypto.ExtractBignum(dmq1, halfModulus); - rsaParameters.InverseQ = Crypto.ExtractBignum(iqmp, halfModulus); - } - - return rsaParameters; - } - finally - { - if (addedRef) - key.DangerousRelease(); - } - } - - [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_GetRsaParameters")] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool GetRsaParameters( - SafeRsaHandle key, - out IntPtr n, - out IntPtr e, - out IntPtr d, - out IntPtr p, - out IntPtr dmp1, - out IntPtr q, - out IntPtr dmq1, - out IntPtr iqmp); - - [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SetRsaParameters")] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool SetRsaParameters( - SafeRsaHandle key, - byte[]? n, - int nLength, - byte[]? e, - int eLength, - byte[]? d, - int dLength, - byte[]? p, - int pLength, - byte[]? dmp1, - int dmp1Length, - byte[]? q, - int qLength, - byte[]? dmq1, - int dmq1Length, - byte[]? iqmp, - int iqmpLength); - - internal enum RsaPadding : int - { - Pkcs1 = 0, - OaepSHA1 = 1, - NoPadding = 2, - } - } -} diff --git a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeRsaHandle.Unix.cs b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeRsaHandle.Unix.cs deleted file mode 100644 index aef516adb3a..00000000000 --- a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeRsaHandle.Unix.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Diagnostics; -using System.Security; -using System.Runtime.InteropServices; - -namespace Microsoft.Win32.SafeHandles -{ - internal sealed class SafeRsaHandle : SafeHandle - { - public SafeRsaHandle() : - base(IntPtr.Zero, ownsHandle: true) - { - } - - protected override bool ReleaseHandle() - { - Interop.Crypto.RsaDestroy(handle); - SetHandle(IntPtr.Zero); - return true; - } - - public override bool IsInvalid - { - get { return handle == IntPtr.Zero; } - } - - internal static SafeRsaHandle DuplicateHandle(IntPtr handle) - { - Debug.Assert(handle != IntPtr.Zero); - - // Reliability: Allocate the SafeHandle before calling RSA_up_ref so - // that we don't lose a tracked reference in low-memory situations. - SafeRsaHandle safeHandle = new SafeRsaHandle(); - - if (!Interop.Crypto.RsaUpRef(handle)) - { - throw Interop.Crypto.CreateOpenSslCryptographicException(); - } - - safeHandle.SetHandle(handle); - return safeHandle; - } - } -} diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/AlgorithmIdentifierAsn.manual.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/AlgorithmIdentifierAsn.manual.cs index c7a4c5784ab..058093035af 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/AlgorithmIdentifierAsn.manual.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/AlgorithmIdentifierAsn.manual.cs @@ -32,7 +32,7 @@ namespace System.Security.Cryptography.Asn1 return Parameters!.Value.Span.SequenceEqual(other.Parameters!.Value.Span); } - internal bool HasNullEquivalentParameters() + internal readonly bool HasNullEquivalentParameters() { return RepresentsNull(Parameters); } diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1Reader/AsnValueReader.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1Reader/AsnValueReader.cs index 6e22b91fb36..a16f66c40c8 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1Reader/AsnValueReader.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1Reader/AsnValueReader.cs @@ -227,5 +227,12 @@ namespace System.Formats.Asn1 throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); } } + + internal static ArraySegment<byte> RentAndEncode(this AsnWriter writer) + { + byte[] rented = CryptoPool.Rent(writer.GetEncodedLength()); + int written = writer.Encode(rented); + return new ArraySegment<byte>(rented, 0, written); + } } } diff --git a/src/libraries/Common/src/System/Security/Cryptography/KeyFormatHelper.Encrypted.cs b/src/libraries/Common/src/System/Security/Cryptography/KeyFormatHelper.Encrypted.cs new file mode 100644 index 00000000000..b4d07d7366a --- /dev/null +++ b/src/libraries/Common/src/System/Security/Cryptography/KeyFormatHelper.Encrypted.cs @@ -0,0 +1,393 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Buffers; +using System.Diagnostics; +using System.Formats.Asn1; +using System.Runtime.InteropServices; +using System.Security.Cryptography.Asn1; + +namespace System.Security.Cryptography +{ + internal static partial class KeyFormatHelper + { + internal static unsafe void ReadEncryptedPkcs8<TRet>( + string[] validOids, + ReadOnlySpan<byte> source, + ReadOnlySpan<char> password, + KeyReader<TRet> keyReader, + out int bytesRead, + out TRet ret) + { + fixed (byte* ptr = &MemoryMarshal.GetReference(source)) + { + using (MemoryManager<byte> manager = new PointerMemoryManager<byte>(ptr, source.Length)) + { + ReadEncryptedPkcs8(validOids, manager.Memory, password, keyReader, out bytesRead, out ret); + } + } + } + + internal static unsafe void ReadEncryptedPkcs8<TRet>( + string[] validOids, + ReadOnlySpan<byte> source, + ReadOnlySpan<byte> passwordBytes, + KeyReader<TRet> keyReader, + out int bytesRead, + out TRet ret) + { + fixed (byte* ptr = &MemoryMarshal.GetReference(source)) + { + using (MemoryManager<byte> manager = new PointerMemoryManager<byte>(ptr, source.Length)) + { + ReadEncryptedPkcs8( + validOids, + manager.Memory, + passwordBytes, + keyReader, + out bytesRead, + out ret); + } + } + } + + private static void ReadEncryptedPkcs8<TRet>( + string[] validOids, + ReadOnlyMemory<byte> source, + ReadOnlySpan<char> password, + KeyReader<TRet> keyReader, + out int bytesRead, + out TRet ret) + { + ReadEncryptedPkcs8( + validOids, + source, + password, + ReadOnlySpan<byte>.Empty, + keyReader, + out bytesRead, + out ret); + } + + private static void ReadEncryptedPkcs8<TRet>( + string[] validOids, + ReadOnlyMemory<byte> source, + ReadOnlySpan<byte> passwordBytes, + KeyReader<TRet> keyReader, + out int bytesRead, + out TRet ret) + { + ReadEncryptedPkcs8( + validOids, + source, + ReadOnlySpan<char>.Empty, + passwordBytes, + keyReader, + out bytesRead, + out ret); + } + + private static void ReadEncryptedPkcs8<TRet>( + string[] validOids, + ReadOnlyMemory<byte> source, + ReadOnlySpan<char> password, + ReadOnlySpan<byte> passwordBytes, + KeyReader<TRet> keyReader, + out int bytesRead, + out TRet ret) + { + int read; + EncryptedPrivateKeyInfoAsn epki; + + try + { + AsnValueReader reader = new AsnValueReader(source.Span, AsnEncodingRules.BER); + read = reader.PeekEncodedValue().Length; + EncryptedPrivateKeyInfoAsn.Decode(ref reader, source, out epki); + } + catch (AsnContentException e) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); + } + + // No supported encryption algorithms produce more bytes of decryption output than there + // were of decryption input. + byte[] decrypted = CryptoPool.Rent(epki.EncryptedData.Length); + Memory<byte> decryptedMemory = decrypted; + + try + { + int decryptedBytes = PasswordBasedEncryption.Decrypt( + epki.EncryptionAlgorithm, + password, + passwordBytes, + epki.EncryptedData.Span, + decrypted); + + decryptedMemory = decryptedMemory.Slice(0, decryptedBytes); + + ReadPkcs8( + validOids, + decryptedMemory, + keyReader, + out int innerRead, + out ret); + + if (innerRead != decryptedMemory.Length) + { + ret = default!; + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); + } + + bytesRead = read; + } + catch (CryptographicException e) + { + throw new CryptographicException(SR.Cryptography_Pkcs8_EncryptedReadFailed, e); + } + finally + { + CryptographicOperations.ZeroMemory(decryptedMemory.Span); + CryptoPool.Return(decrypted, clearSize: 0); + } + } + + internal static AsnWriter WriteEncryptedPkcs8( + ReadOnlySpan<char> password, + AsnWriter pkcs8Writer, + PbeParameters pbeParameters) + { + return WriteEncryptedPkcs8( + password, + ReadOnlySpan<byte>.Empty, + pkcs8Writer, + pbeParameters); + } + + internal static AsnWriter WriteEncryptedPkcs8( + ReadOnlySpan<byte> passwordBytes, + AsnWriter pkcs8Writer, + PbeParameters pbeParameters) + { + return WriteEncryptedPkcs8( + ReadOnlySpan<char>.Empty, + passwordBytes, + pkcs8Writer, + pbeParameters); + } + + private static AsnWriter WriteEncryptedPkcs8( + ReadOnlySpan<char> password, + ReadOnlySpan<byte> passwordBytes, + AsnWriter pkcs8Writer, + PbeParameters pbeParameters) + { + PasswordBasedEncryption.InitiateEncryption( + pbeParameters, + out SymmetricAlgorithm cipher, + out string hmacOid, + out string encryptionAlgorithmOid, + out bool isPkcs12); + + byte[]? encryptedRent = null; + Span<byte> encryptedSpan = default; + AsnWriter? writer = null; + + try + { + Debug.Assert(cipher.BlockSize <= 128, $"Encountered unexpected block size: {cipher.BlockSize}"); + Span<byte> iv = stackalloc byte[cipher.BlockSize / 8]; + Span<byte> salt = stackalloc byte[16]; + + // We need at least one block size beyond the input data size. + encryptedRent = CryptoPool.Rent( + checked(pkcs8Writer.GetEncodedLength() + (cipher.BlockSize / 8))); + + RandomNumberGenerator.Fill(salt); + + int written = PasswordBasedEncryption.Encrypt( + password, + passwordBytes, + cipher, + isPkcs12, + pkcs8Writer, + pbeParameters, + salt, + encryptedRent, + iv); + + encryptedSpan = encryptedRent.AsSpan(0, written); + + writer = new AsnWriter(AsnEncodingRules.DER); + + // PKCS8 EncryptedPrivateKeyInfo + writer.PushSequence(); + + // EncryptedPrivateKeyInfo.encryptionAlgorithm + PasswordBasedEncryption.WritePbeAlgorithmIdentifier( + writer, + isPkcs12, + encryptionAlgorithmOid, + salt, + pbeParameters.IterationCount, + hmacOid, + iv); + + // encryptedData + writer.WriteOctetString(encryptedSpan); + writer.PopSequence(); + + return writer; + } + finally + { + CryptographicOperations.ZeroMemory(encryptedSpan); + CryptoPool.Return(encryptedRent!, clearSize: 0); + + cipher.Dispose(); + } + } + + internal static ArraySegment<byte> DecryptPkcs8( + ReadOnlySpan<char> inputPassword, + ReadOnlyMemory<byte> source, + out int bytesRead) + { + return DecryptPkcs8( + inputPassword, + ReadOnlySpan<byte>.Empty, + source, + out bytesRead); + } + + internal static ArraySegment<byte> DecryptPkcs8( + ReadOnlySpan<byte> inputPasswordBytes, + ReadOnlyMemory<byte> source, + out int bytesRead) + { + return DecryptPkcs8( + ReadOnlySpan<char>.Empty, + inputPasswordBytes, + source, + out bytesRead); + } + + private static ArraySegment<byte> DecryptPkcs8( + ReadOnlySpan<char> inputPassword, + ReadOnlySpan<byte> inputPasswordBytes, + ReadOnlyMemory<byte> source, + out int bytesRead) + { + int localRead; + EncryptedPrivateKeyInfoAsn epki; + + try + { + AsnValueReader reader = new AsnValueReader(source.Span, AsnEncodingRules.BER); + localRead = reader.PeekEncodedValue().Length; + EncryptedPrivateKeyInfoAsn.Decode(ref reader, source, out epki); + } + catch (AsnContentException e) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); + } + + // No supported encryption algorithms produce more bytes of decryption output than there + // were of decryption input. + byte[] decrypted = CryptoPool.Rent(epki.EncryptedData.Length); + + try + { + int decryptedBytes = PasswordBasedEncryption.Decrypt( + epki.EncryptionAlgorithm, + inputPassword, + inputPasswordBytes, + epki.EncryptedData.Span, + decrypted); + + bytesRead = localRead; + + return new ArraySegment<byte>(decrypted, 0, decryptedBytes); + } + catch (CryptographicException e) + { + CryptoPool.Return(decrypted); + throw new CryptographicException(SR.Cryptography_Pkcs8_EncryptedReadFailed, e); + } + } + + internal static AsnWriter ReencryptPkcs8( + ReadOnlySpan<char> inputPassword, + ReadOnlyMemory<byte> current, + ReadOnlySpan<char> newPassword, + PbeParameters pbeParameters) + { + ArraySegment<byte> decrypted = DecryptPkcs8( + inputPassword, + current, + out int bytesRead); + + try + { + if (bytesRead != current.Length) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); + } + + AsnWriter pkcs8Writer = new AsnWriter(AsnEncodingRules.BER); + pkcs8Writer.WriteEncodedValueForCrypto(decrypted); + + return WriteEncryptedPkcs8( + newPassword, + pkcs8Writer, + pbeParameters); + } + catch (CryptographicException e) + { + throw new CryptographicException(SR.Cryptography_Pkcs8_EncryptedReadFailed, e); + } + finally + { + CryptographicOperations.ZeroMemory(decrypted); + CryptoPool.Return(decrypted.Array!, clearSize: 0); + } + } + + internal static AsnWriter ReencryptPkcs8( + ReadOnlySpan<char> inputPassword, + ReadOnlyMemory<byte> current, + ReadOnlySpan<byte> newPasswordBytes, + PbeParameters pbeParameters) + { + ArraySegment<byte> decrypted = DecryptPkcs8( + inputPassword, + current, + out int bytesRead); + + try + { + if (bytesRead != current.Length) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); + } + + AsnWriter pkcs8Writer = new AsnWriter(AsnEncodingRules.BER); + pkcs8Writer.WriteEncodedValueForCrypto(decrypted); + + return WriteEncryptedPkcs8( + newPasswordBytes, + pkcs8Writer, + pbeParameters); + } + catch (CryptographicException e) + { + throw new CryptographicException(SR.Cryptography_Pkcs8_EncryptedReadFailed, e); + } + finally + { + CryptographicOperations.ZeroMemory(decrypted); + CryptoPool.Return(decrypted.Array!, clearSize: 0); + } + } + } +} diff --git a/src/libraries/Common/src/System/Security/Cryptography/KeyFormatHelper.cs b/src/libraries/Common/src/System/Security/Cryptography/KeyFormatHelper.cs index 66981c2bd41..e175342014a 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/KeyFormatHelper.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/KeyFormatHelper.cs @@ -9,7 +9,7 @@ using System.Security.Cryptography.Asn1; namespace System.Security.Cryptography { - internal static class KeyFormatHelper + internal static partial class KeyFormatHelper { internal delegate void KeyReader<TRet>(ReadOnlyMemory<byte> key, in AlgorithmIdentifierAsn algId, out TRet ret); @@ -158,147 +158,6 @@ namespace System.Security.Cryptography } } - internal static unsafe void ReadEncryptedPkcs8<TRet>( - string[] validOids, - ReadOnlySpan<byte> source, - ReadOnlySpan<char> password, - KeyReader<TRet> keyReader, - out int bytesRead, - out TRet ret) - { - fixed (byte* ptr = &MemoryMarshal.GetReference(source)) - { - using (MemoryManager<byte> manager = new PointerMemoryManager<byte>(ptr, source.Length)) - { - ReadEncryptedPkcs8(validOids, manager.Memory, password, keyReader, out bytesRead, out ret); - } - } - } - - internal static unsafe void ReadEncryptedPkcs8<TRet>( - string[] validOids, - ReadOnlySpan<byte> source, - ReadOnlySpan<byte> passwordBytes, - KeyReader<TRet> keyReader, - out int bytesRead, - out TRet ret) - { - fixed (byte* ptr = &MemoryMarshal.GetReference(source)) - { - using (MemoryManager<byte> manager = new PointerMemoryManager<byte>(ptr, source.Length)) - { - ReadEncryptedPkcs8( - validOids, - manager.Memory, - passwordBytes, - keyReader, - out bytesRead, - out ret); - } - } - } - - private static void ReadEncryptedPkcs8<TRet>( - string[] validOids, - ReadOnlyMemory<byte> source, - ReadOnlySpan<char> password, - KeyReader<TRet> keyReader, - out int bytesRead, - out TRet ret) - { - ReadEncryptedPkcs8( - validOids, - source, - password, - ReadOnlySpan<byte>.Empty, - keyReader, - out bytesRead, - out ret); - } - - private static void ReadEncryptedPkcs8<TRet>( - string[] validOids, - ReadOnlyMemory<byte> source, - ReadOnlySpan<byte> passwordBytes, - KeyReader<TRet> keyReader, - out int bytesRead, - out TRet ret) - { - ReadEncryptedPkcs8( - validOids, - source, - ReadOnlySpan<char>.Empty, - passwordBytes, - keyReader, - out bytesRead, - out ret); - } - - private static void ReadEncryptedPkcs8<TRet>( - string[] validOids, - ReadOnlyMemory<byte> source, - ReadOnlySpan<char> password, - ReadOnlySpan<byte> passwordBytes, - KeyReader<TRet> keyReader, - out int bytesRead, - out TRet ret) - { - int read; - EncryptedPrivateKeyInfoAsn epki; - - try - { - AsnValueReader reader = new AsnValueReader(source.Span, AsnEncodingRules.BER); - read = reader.PeekEncodedValue().Length; - EncryptedPrivateKeyInfoAsn.Decode(ref reader, source, out epki); - } - catch (AsnContentException e) - { - throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); - } - - // No supported encryption algorithms produce more bytes of decryption output than there - // were of decryption input. - byte[] decrypted = CryptoPool.Rent(epki.EncryptedData.Length); - Memory<byte> decryptedMemory = decrypted; - - try - { - int decryptedBytes = PasswordBasedEncryption.Decrypt( - epki.EncryptionAlgorithm, - password, - passwordBytes, - epki.EncryptedData.Span, - decrypted); - - decryptedMemory = decryptedMemory.Slice(0, decryptedBytes); - - ReadPkcs8( - validOids, - decryptedMemory, - keyReader, - out int innerRead, - out ret); - - if (innerRead != decryptedMemory.Length) - { - ret = default!; - throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); - } - - bytesRead = read; - } - catch (CryptographicException e) - { - throw new CryptographicException(SR.Cryptography_Pkcs8_EncryptedReadFailed, e); - } - finally - { - CryptographicOperations.ZeroMemory(decryptedMemory.Span); - CryptoPool.Return(decrypted, clearSize: 0); - } - } - internal static AsnWriter WritePkcs8( AsnWriter algorithmIdentifierWriter, AsnWriter privateKeyWriter, @@ -345,243 +204,5 @@ namespace System.Security.Cryptography writer.PopSequence(); return writer; } - - internal static AsnWriter WriteEncryptedPkcs8( - ReadOnlySpan<char> password, - AsnWriter pkcs8Writer, - PbeParameters pbeParameters) - { - return WriteEncryptedPkcs8( - password, - ReadOnlySpan<byte>.Empty, - pkcs8Writer, - pbeParameters); - } - - internal static AsnWriter WriteEncryptedPkcs8( - ReadOnlySpan<byte> passwordBytes, - AsnWriter pkcs8Writer, - PbeParameters pbeParameters) - { - return WriteEncryptedPkcs8( - ReadOnlySpan<char>.Empty, - passwordBytes, - pkcs8Writer, - pbeParameters); - } - - private static AsnWriter WriteEncryptedPkcs8( - ReadOnlySpan<char> password, - ReadOnlySpan<byte> passwordBytes, - AsnWriter pkcs8Writer, - PbeParameters pbeParameters) - { - PasswordBasedEncryption.InitiateEncryption( - pbeParameters, - out SymmetricAlgorithm cipher, - out string hmacOid, - out string encryptionAlgorithmOid, - out bool isPkcs12); - - byte[]? encryptedRent = null; - Span<byte> encryptedSpan = default; - AsnWriter? writer = null; - - try - { - Debug.Assert(cipher.BlockSize <= 128, $"Encountered unexpected block size: {cipher.BlockSize}"); - Span<byte> iv = stackalloc byte[cipher.BlockSize / 8]; - Span<byte> salt = stackalloc byte[16]; - - // We need at least one block size beyond the input data size. - encryptedRent = CryptoPool.Rent( - checked(pkcs8Writer.GetEncodedLength() + (cipher.BlockSize / 8))); - - RandomNumberGenerator.Fill(salt); - - int written = PasswordBasedEncryption.Encrypt( - password, - passwordBytes, - cipher, - isPkcs12, - pkcs8Writer, - pbeParameters, - salt, - encryptedRent, - iv); - - encryptedSpan = encryptedRent.AsSpan(0, written); - - writer = new AsnWriter(AsnEncodingRules.DER); - - // PKCS8 EncryptedPrivateKeyInfo - writer.PushSequence(); - - // EncryptedPrivateKeyInfo.encryptionAlgorithm - PasswordBasedEncryption.WritePbeAlgorithmIdentifier( - writer, - isPkcs12, - encryptionAlgorithmOid, - salt, - pbeParameters.IterationCount, - hmacOid, - iv); - - // encryptedData - writer.WriteOctetString(encryptedSpan); - writer.PopSequence(); - - return writer; - } - finally - { - CryptographicOperations.ZeroMemory(encryptedSpan); - CryptoPool.Return(encryptedRent!, clearSize: 0); - - cipher.Dispose(); - } - } - - internal static ArraySegment<byte> DecryptPkcs8( - ReadOnlySpan<char> inputPassword, - ReadOnlyMemory<byte> source, - out int bytesRead) - { - return DecryptPkcs8( - inputPassword, - ReadOnlySpan<byte>.Empty, - source, - out bytesRead); - } - - internal static ArraySegment<byte> DecryptPkcs8( - ReadOnlySpan<byte> inputPasswordBytes, - ReadOnlyMemory<byte> source, - out int bytesRead) - { - return DecryptPkcs8( - ReadOnlySpan<char>.Empty, - inputPasswordBytes, - source, - out bytesRead); - } - - private static ArraySegment<byte> DecryptPkcs8( - ReadOnlySpan<char> inputPassword, - ReadOnlySpan<byte> inputPasswordBytes, - ReadOnlyMemory<byte> source, - out int bytesRead) - { - int localRead; - EncryptedPrivateKeyInfoAsn epki; - - try - { - AsnValueReader reader = new AsnValueReader(source.Span, AsnEncodingRules.BER); - localRead = reader.PeekEncodedValue().Length; - EncryptedPrivateKeyInfoAsn.Decode(ref reader, source, out epki); - } - catch (AsnContentException e) - { - throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); - } - - // No supported encryption algorithms produce more bytes of decryption output than there - // were of decryption input. - byte[] decrypted = CryptoPool.Rent(epki.EncryptedData.Length); - - try - { - int decryptedBytes = PasswordBasedEncryption.Decrypt( - epki.EncryptionAlgorithm, - inputPassword, - inputPasswordBytes, - epki.EncryptedData.Span, - decrypted); - - bytesRead = localRead; - - return new ArraySegment<byte>(decrypted, 0, decryptedBytes); - } - catch (CryptographicException e) - { - CryptoPool.Return(decrypted); - throw new CryptographicException(SR.Cryptography_Pkcs8_EncryptedReadFailed, e); - } - } - - internal static AsnWriter ReencryptPkcs8( - ReadOnlySpan<char> inputPassword, - ReadOnlyMemory<byte> current, - ReadOnlySpan<char> newPassword, - PbeParameters pbeParameters) - { - ArraySegment<byte> decrypted = DecryptPkcs8( - inputPassword, - current, - out int bytesRead); - - try - { - if (bytesRead != current.Length) - { - throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); - } - - AsnWriter pkcs8Writer = new AsnWriter(AsnEncodingRules.BER); - pkcs8Writer.WriteEncodedValueForCrypto(decrypted); - - return WriteEncryptedPkcs8( - newPassword, - pkcs8Writer, - pbeParameters); - } - catch (CryptographicException e) - { - throw new CryptographicException(SR.Cryptography_Pkcs8_EncryptedReadFailed, e); - } - finally - { - CryptographicOperations.ZeroMemory(decrypted); - CryptoPool.Return(decrypted.Array!, clearSize: 0); - } - } - - internal static AsnWriter ReencryptPkcs8( - ReadOnlySpan<char> inputPassword, - ReadOnlyMemory<byte> current, - ReadOnlySpan<byte> newPasswordBytes, - PbeParameters pbeParameters) - { - ArraySegment<byte> decrypted = DecryptPkcs8( - inputPassword, - current, - out int bytesRead); - - try - { - if (bytesRead != current.Length) - { - throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); - } - - AsnWriter pkcs8Writer = new AsnWriter(AsnEncodingRules.BER); - pkcs8Writer.WriteEncodedValueForCrypto(decrypted); - - return WriteEncryptedPkcs8( - newPasswordBytes, - pkcs8Writer, - pbeParameters); - } - catch (CryptographicException e) - { - throw new CryptographicException(SR.Cryptography_Pkcs8_EncryptedReadFailed, e); - } - finally - { - CryptographicOperations.ZeroMemory(decrypted); - CryptoPool.Return(decrypted.Array!, clearSize: 0); - } - } } } diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSAKeyFormatHelper.Encrypted.cs b/src/libraries/Common/src/System/Security/Cryptography/RSAKeyFormatHelper.Encrypted.cs new file mode 100644 index 00000000000..0ce3c2e5037 --- /dev/null +++ b/src/libraries/Common/src/System/Security/Cryptography/RSAKeyFormatHelper.Encrypted.cs @@ -0,0 +1,38 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Security.Cryptography +{ + internal static partial class RSAKeyFormatHelper + { + internal static void ReadEncryptedPkcs8( + ReadOnlySpan<byte> source, + ReadOnlySpan<char> password, + out int bytesRead, + out RSAParameters key) + { + KeyFormatHelper.ReadEncryptedPkcs8<RSAParameters>( + s_validOids, + source, + password, + FromPkcs1PrivateKey, + out bytesRead, + out key); + } + + internal static void ReadEncryptedPkcs8( + ReadOnlySpan<byte> source, + ReadOnlySpan<byte> passwordBytes, + out int bytesRead, + out RSAParameters key) + { + KeyFormatHelper.ReadEncryptedPkcs8<RSAParameters>( + s_validOids, + source, + passwordBytes, + FromPkcs1PrivateKey, + out bytesRead, + out key); + } + } +} diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSAKeyFormatHelper.cs b/src/libraries/Common/src/System/Security/Cryptography/RSAKeyFormatHelper.cs index e7285c21f94..e5c776da092 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSAKeyFormatHelper.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSAKeyFormatHelper.cs @@ -1,13 +1,14 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Buffers; using System.Diagnostics; using System.Formats.Asn1; using System.Security.Cryptography.Asn1; namespace System.Security.Cryptography { - internal static class RSAKeyFormatHelper + internal static partial class RSAKeyFormatHelper { private static readonly string[] s_validOids = { @@ -111,6 +112,25 @@ namespace System.Security.Cryptography out bytesRead); } + /// <summary> + /// Checks that a SubjectPublicKeyInfo represents an RSA key. + /// </summary> + /// <returns>The number of bytes read from <paramref name="source"/>.</returns> + internal static unsafe int CheckSubjectPublicKeyInfo(ReadOnlySpan<byte> source) + { + int bytesRead; + + fixed (byte* ptr = source) + { + using (MemoryManager<byte> manager = new PointerMemoryManager<byte>(ptr, source.Length)) + { + _ = ReadSubjectPublicKeyInfo(manager.Memory, out bytesRead); + } + } + + return bytesRead; + } + public static void ReadPkcs8( ReadOnlySpan<byte> source, out int bytesRead, @@ -134,34 +154,23 @@ namespace System.Security.Cryptography out bytesRead); } - internal static void ReadEncryptedPkcs8( - ReadOnlySpan<byte> source, - ReadOnlySpan<char> password, - out int bytesRead, - out RSAParameters key) + /// <summary> + /// Checks that a Pkcs8PrivateKeyInfo represents an RSA key. + /// </summary> + /// <returns>The number of bytes read from <paramref name="source"/>.</returns> + internal static unsafe int CheckPkcs8(ReadOnlySpan<byte> source) { - KeyFormatHelper.ReadEncryptedPkcs8<RSAParameters>( - s_validOids, - source, - password, - FromPkcs1PrivateKey, - out bytesRead, - out key); - } + int bytesRead; - internal static void ReadEncryptedPkcs8( - ReadOnlySpan<byte> source, - ReadOnlySpan<byte> passwordBytes, - out int bytesRead, - out RSAParameters key) - { - KeyFormatHelper.ReadEncryptedPkcs8<RSAParameters>( - s_validOids, - source, - passwordBytes, - FromPkcs1PrivateKey, - out bytesRead, - out key); + fixed (byte* ptr = source) + { + using (MemoryManager<byte> manager = new PointerMemoryManager<byte>(ptr, source.Length)) + { + _ = ReadPkcs8(manager.Memory, out bytesRead); + } + } + + return bytesRead; } internal static AsnWriter WriteSubjectPublicKeyInfo(ReadOnlySpan<byte> pkcs1PublicKey) diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs b/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs index 40381076b03..d6d66c78ae1 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs @@ -5,6 +5,7 @@ using System.Buffers; using System.Diagnostics; using System.Formats.Asn1; using System.IO; +using System.Security.Cryptography.Asn1; using Microsoft.Win32.SafeHandles; using Internal.Cryptography; @@ -278,81 +279,211 @@ namespace System.Security.Cryptography return true; } - public override RSAParameters ExportParameters(bool includePrivateParameters) + private delegate T ExportPrivateKeyFunc<T>(ReadOnlyMemory<byte> pkcs8, ReadOnlyMemory<byte> pkcs1); + + private delegate ReadOnlyMemory<byte> TryExportPrivateKeySelector( + ReadOnlyMemory<byte> pkcs8, + ReadOnlyMemory<byte> pkcs1); + + private T ExportPrivateKey<T>(ExportPrivateKeyFunc<T> exporter) { // It's entirely possible that this line will cause the key to be generated in the first place. SafeEvpPKeyHandle key = GetKey(); - RSAParameters rsaParameters = Interop.Crypto.ExportRsaParameters(key, includePrivateParameters); - bool hasPrivateKey = rsaParameters.D != null; + ArraySegment<byte> p8 = Interop.Crypto.RentEncodePkcs8PrivateKey(key); - if (hasPrivateKey != includePrivateParameters || !HasConsistentPrivateKey(ref rsaParameters)) + try { - throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey); + ReadOnlyMemory<byte> pkcs1 = VerifyPkcs8(p8); + return exporter(p8, pkcs1); + } + finally + { + CryptoPool.Return(p8); } + } + + private bool TryExportPrivateKey(TryExportPrivateKeySelector selector, Span<byte> destination, out int bytesWritten) + { + // It's entirely possible that this line will cause the key to be generated in the first place. + SafeEvpPKeyHandle key = GetKey(); + + ArraySegment<byte> p8 = Interop.Crypto.RentEncodePkcs8PrivateKey(key); - return rsaParameters; + try + { + ReadOnlyMemory<byte> pkcs1 = VerifyPkcs8(p8); + ReadOnlyMemory<byte> selected = selector(p8, pkcs1); + return selected.Span.TryCopyToDestination(destination, out bytesWritten); + } + finally + { + CryptoPool.Return(p8); + } } - public override void ImportParameters(RSAParameters parameters) + private T ExportPublicKey<T>(Func<ReadOnlyMemory<byte>, T> exporter) { - ValidateParameters(ref parameters); - ThrowIfDisposed(); + // It's entirely possible that this line will cause the key to be generated in the first place. + SafeEvpPKeyHandle key = GetKey(); + + ArraySegment<byte> spki = Interop.Crypto.RentEncodeSubjectPublicKeyInfo(key); + + try + { + return exporter(spki); + } + finally + { + CryptoPool.Return(spki); + } + } - SafeRsaHandle key = Interop.Crypto.RsaCreate(); - SafeEvpPKeyHandle pkey = Interop.Crypto.EvpPkeyCreate(); - bool imported = false; + private bool TryExportPublicKey( + Func<ReadOnlyMemory<byte>, ReadOnlyMemory<byte>>? transform, + Span<byte> destination, + out int bytesWritten) + { + // It's entirely possible that this line will cause the key to be generated in the first place. + SafeEvpPKeyHandle key = GetKey(); - Interop.Crypto.CheckValidOpenSslHandle(key); + ArraySegment<byte> spki = Interop.Crypto.RentEncodeSubjectPublicKeyInfo(key); try { - if (!Interop.Crypto.SetRsaParameters( - key, - parameters.Modulus, - parameters.Modulus != null ? parameters.Modulus.Length : 0, - parameters.Exponent, - parameters.Exponent != null ? parameters.Exponent.Length : 0, - parameters.D, - parameters.D != null ? parameters.D.Length : 0, - parameters.P, - parameters.P != null ? parameters.P.Length : 0, - parameters.DP, - parameters.DP != null ? parameters.DP.Length : 0, - parameters.Q, - parameters.Q != null ? parameters.Q.Length : 0, - parameters.DQ, - parameters.DQ != null ? parameters.DQ.Length : 0, - parameters.InverseQ, - parameters.InverseQ != null ? parameters.InverseQ.Length : 0)) + ReadOnlyMemory<byte> data = spki; + + if (transform != null) { - throw Interop.Crypto.CreateOpenSslCryptographicException(); + data = transform(data); } - imported = true; + return data.Span.TryCopyToDestination(destination, out bytesWritten); } finally { - if (!imported) - { - key.Dispose(); - } + CryptoPool.Return(spki); } + } + + public override bool TryExportPkcs8PrivateKey(Span<byte> destination, out int bytesWritten) + { + return TryExportPrivateKey(static (pkcs8, pkcs1) => pkcs8, destination, out bytesWritten); + } + + public override byte[] ExportPkcs8PrivateKey() + { + return ExportPrivateKey(static (pkcs8, pkcs1) => pkcs8.ToArray()); + } + + public override bool TryExportRSAPrivateKey(Span<byte> destination, out int bytesWritten) + { + return TryExportPrivateKey(static (pkcs8, pkcs1) => pkcs1, destination, out bytesWritten); + } + + public override byte[] ExportRSAPrivateKey() + { + return ExportPrivateKey(static (pkcs8, pkcs1) => pkcs1.ToArray()); + } + + public override byte[] ExportRSAPublicKey() + { + return ExportPublicKey( + static spki => + { + ReadOnlyMemory<byte> pkcs1 = RSAKeyFormatHelper.ReadSubjectPublicKeyInfo(spki, out int read); + Debug.Assert(read == spki.Length); + return pkcs1.ToArray(); + }); + } + + public override bool TryExportRSAPublicKey(Span<byte> destination, out int bytesWritten) + { + return TryExportPublicKey( + spki => + { + ReadOnlyMemory<byte> pkcs1 = RSAKeyFormatHelper.ReadSubjectPublicKeyInfo(spki, out int read); + Debug.Assert(read == spki.Length); + return pkcs1; + }, + destination, + out bytesWritten); + } + + public override byte[] ExportSubjectPublicKeyInfo() + { + return ExportPublicKey(static spki => spki.ToArray()); + } + + public override bool TryExportSubjectPublicKeyInfo(Span<byte> destination, out int bytesWritten) + { + return TryExportPublicKey( + transform: null, + destination, + out bytesWritten); + } - if (!Interop.Crypto.EvpPkeySetRsa(pkey, key)) + public override RSAParameters ExportParameters(bool includePrivateParameters) + { + if (includePrivateParameters) { - pkey.Dispose(); - key.Dispose(); - throw Interop.Crypto.CreateOpenSslCryptographicException(); + return ExportPrivateKey( + static (pkcs8, pkcs1) => + { + AlgorithmIdentifierAsn algId = default; + RSAParameters ret; + RSAKeyFormatHelper.FromPkcs1PrivateKey(pkcs1, in algId, out ret); + return ret; + }); } - key.Dispose(); - FreeKey(); - _key = new Lazy<SafeEvpPKeyHandle>(pkey); + return ExportPublicKey( + static spki => + { + RSAParameters ret; + RSAKeyFormatHelper.ReadSubjectPublicKeyInfo( + spki.Span, + out int read, + out ret); + + Debug.Assert(read == spki.Length); + return ret; + }); + } - // Use ForceSet instead of the property setter to ensure that LegalKeySizes doesn't interfere - // with the already loaded key. - ForceSetKeySize(BitsPerByte * Interop.Crypto.EvpPKeySize(pkey)); + public override void ImportParameters(RSAParameters parameters) + { + ValidateParameters(ref parameters); + ThrowIfDisposed(); + + if (parameters.D != null) + { + AsnWriter writer = RSAKeyFormatHelper.WritePkcs8PrivateKey(parameters); + ArraySegment<byte> pkcs8 = writer.RentAndEncode(); + + try + { + ImportPkcs8PrivateKey(pkcs8, checkAlgorithm: false, out _); + } + finally + { + CryptoPool.Return(pkcs8); + } + } + else + { + AsnWriter writer = RSAKeyFormatHelper.WriteSubjectPublicKeyInfo(parameters); + ArraySegment<byte> spki = writer.RentAndEncode(); + + try + { + ImportSubjectPublicKeyInfo(spki, checkAlgorithm: false, out _); + } + finally + { + CryptoPool.Return(spki); + } + } } public override void ImportRSAPublicKey(ReadOnlySpan<byte> source, out int bytesRead) @@ -375,27 +506,52 @@ namespace System.Security.Cryptography throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); } - SafeEvpPKeyHandle pkey = Interop.Crypto.EvpPkeyCreate(); - SafeRsaHandle key = Interop.Crypto.DecodeRsaPublicKey(source.Slice(0, read)); - - Interop.Crypto.CheckValidOpenSslHandle(key); + AsnWriter writer = RSAKeyFormatHelper.WriteSubjectPublicKeyInfo(source.Slice(0, read)); + ArraySegment<byte> spki = writer.RentAndEncode(); - if (!Interop.Crypto.EvpPkeySetRsa(pkey, key)) + try + { + ImportSubjectPublicKeyInfo(spki, checkAlgorithm: false, out _); + } + finally { - key.Dispose(); - pkey.Dispose(); - throw Interop.Crypto.CreateOpenSslCryptographicException(); + CryptoPool.Return(spki); } - key.Dispose(); + bytesRead = read; + } - FreeKey(); - _key = new Lazy<SafeEvpPKeyHandle>(pkey); + public override void ImportSubjectPublicKeyInfo( + ReadOnlySpan<byte> source, + out int bytesRead) + { + ThrowIfDisposed(); - // Use ForceSet instead of the property setter to ensure that LegalKeySizes doesn't interfere - // with the already loaded key. - ForceSetKeySize(BitsPerByte * Interop.Crypto.EvpPKeySize(pkey)); + ImportSubjectPublicKeyInfo(source, checkAlgorithm: true, out bytesRead); + } + + private void ImportSubjectPublicKeyInfo( + ReadOnlySpan<byte> source, + bool checkAlgorithm, + out int bytesRead) + { + int read; + + if (checkAlgorithm) + { + read = RSAKeyFormatHelper.CheckSubjectPublicKeyInfo(source); + } + else + { + read = source.Length; + } + + SafeEvpPKeyHandle newKey = Interop.Crypto.DecodeSubjectPublicKeyInfo( + source.Slice(0, read), + Interop.Crypto.EvpAlgorithmId.RSA); + Debug.Assert(!newKey.IsInvalid); + SetKey(newKey); bytesRead = read; } @@ -417,6 +573,70 @@ namespace System.Security.Cryptography base.ImportEncryptedPkcs8PrivateKey(password, source, out bytesRead); } + public override void ImportPkcs8PrivateKey(ReadOnlySpan<byte> source, out int bytesRead) + { + ThrowIfDisposed(); + + ImportPkcs8PrivateKey(source, checkAlgorithm: true, out bytesRead); + } + + private void ImportPkcs8PrivateKey(ReadOnlySpan<byte> source, bool checkAlgorithm, out int bytesRead) + { + int read; + + if (checkAlgorithm) + { + read = RSAKeyFormatHelper.CheckPkcs8(source); + } + else + { + read = source.Length; + } + + SafeEvpPKeyHandle newKey = Interop.Crypto.DecodePkcs8PrivateKey( + source.Slice(0, read), + Interop.Crypto.EvpAlgorithmId.RSA); + + Debug.Assert(!newKey.IsInvalid); + SetKey(newKey); + bytesRead = read; + } + + public override void ImportRSAPrivateKey(ReadOnlySpan<byte> source, out int bytesRead) + { + ThrowIfDisposed(); + + int read; + + try + { + AsnDecoder.ReadEncodedValue( + source, + AsnEncodingRules.BER, + out _, + out _, + out read); + } + catch (AsnContentException e) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); + } + + AsnWriter writer = RSAKeyFormatHelper.WritePkcs8PrivateKey(source.Slice(0, read)); + ArraySegment<byte> pkcs8 = writer.RentAndEncode(); + + try + { + ImportPkcs8PrivateKey(pkcs8, checkAlgorithm: false, out _); + } + finally + { + CryptoPool.Return(pkcs8); + } + + bytesRead = read; + } + protected override void Dispose(bool disposing) { if (disposing) @@ -437,6 +657,18 @@ namespace System.Security.Cryptography } } + [System.Diagnostics.CodeAnalysis.MemberNotNull(nameof(_key))] + private void SetKey(SafeEvpPKeyHandle newKey) + { + Debug.Assert(!newKey.IsInvalid); + FreeKey(); + _key = new Lazy<SafeEvpPKeyHandle>(newKey); + + // Use ForceSet instead of the property setter to ensure that LegalKeySizes doesn't interfere + // with the already loaded key. + ForceSetKeySize(BitsPerByte * Interop.Crypto.EvpPKeySize(newKey)); + } + private static void ValidateParameters(ref RSAParameters parameters) { if (parameters.Modulus == null || parameters.Exponent == null) @@ -646,6 +878,26 @@ namespace System.Security.Cryptography signature); } + private static ReadOnlyMemory<byte> VerifyPkcs8(ReadOnlyMemory<byte> pkcs8) + { + // OpenSSL 1.1.1 will export RSA public keys as a PKCS#8, but this makes a broken structure. + // + // So, crack it back open. If we can walk the payload it's valid, otherwise throw the + // "there's no private key" exception. + + try + { + ReadOnlyMemory<byte> pkcs1Priv = RSAKeyFormatHelper.ReadPkcs8(pkcs8, out int read); + Debug.Assert(read == pkcs8.Length); + _ = RSAPrivateKeyAsn.Decode(pkcs1Priv, AsnEncodingRules.BER); + return pkcs1Priv; + } + catch (CryptographicException) + { + throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey); + } + } + private static void ValidatePadding(RSAEncryptionPadding padding) { if (padding == null) diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/CMakeLists.txt b/src/libraries/Native/Unix/System.Security.Cryptography.Native/CMakeLists.txt index f6f12e2d7f5..37a7f5ccc5b 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/CMakeLists.txt +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/CMakeLists.txt @@ -37,7 +37,6 @@ set(NATIVECRYPTO_SOURCES pal_hmac.c pal_ocsp.c pal_pkcs7.c - pal_rsa.c pal_ssl.c pal_x509.c pal_x509_name.c diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/apibridge.c b/src/libraries/Native/Unix/System.Security.Cryptography.Native/apibridge.c index 0414eb2b271..15df621f7a7 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/apibridge.c +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/apibridge.c @@ -825,4 +825,63 @@ int local_RSA_test_flags(const RSA *r, int flags) return r->flags & flags; } +int local_EVP_PKEY_check(EVP_PKEY_CTX* ctx) +{ + EVP_PKEY* pkey = EVP_PKEY_CTX_get0_pkey(ctx); + + if (pkey == NULL) + { + ERR_put_error(ERR_LIB_EVP, 0, EVP_R_INPUT_NOT_INITIALIZED, __FILE__, __LINE__); + return -1; + } + + int id = EVP_PKEY_get_base_id(pkey); + + switch (id) + { + case NID_rsaEncryption: + { + const RSA* rsa = EVP_PKEY_get0_RSA(pkey); + + if (rsa != NULL) + { + return RSA_check_key(rsa); + } + + break; + } + default: + ERR_put_error(ERR_LIB_EVP, 0, EVP_R_UNSUPPORTED_ALGORITHM, __FILE__, __LINE__); + return -1; + } + + ERR_put_error(ERR_LIB_EVP, 0, EVP_R_NO_KEY_SET, __FILE__, __LINE__); + return -1; +} + +int local_EVP_PKEY_public_check(EVP_PKEY_CTX* ctx) +{ + EVP_PKEY* pkey = EVP_PKEY_CTX_get0_pkey(ctx); + + if (pkey == NULL) + { + ERR_put_error(ERR_LIB_EVP, 0, EVP_R_INPUT_NOT_INITIALIZED, __FILE__, __LINE__); + return -1; + } + + int id = EVP_PKEY_get_base_id(pkey); + + switch (id) + { + case NID_rsaEncryption: + { + ERR_put_error(ERR_LIB_EVP, 0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE, __FILE__, __LINE__); + return -2; + } + default: + ERR_put_error(ERR_LIB_EVP, 0, EVP_R_UNSUPPORTED_ALGORITHM, __FILE__, __LINE__); + return -1; + } +} + #endif diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/apibridge.h b/src/libraries/Native/Unix/System.Security.Cryptography.Native/apibridge.h index 968e12dad15..3998f1abbf3 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/apibridge.h +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/apibridge.h @@ -15,7 +15,9 @@ int32_t local_DSA_set0_pqg(DSA* dsa, BIGNUM* bnP, BIGNUM* bnQ, BIGNUM* bnG); void local_EVP_CIPHER_CTX_free(EVP_CIPHER_CTX* ctx); EVP_CIPHER_CTX* local_EVP_CIPHER_CTX_new(void); int32_t local_EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX* ctx); +int local_EVP_PKEY_check(EVP_PKEY_CTX* ctx); RSA* local_EVP_PKEY_get0_RSA(EVP_PKEY* pkey); +int local_EVP_PKEY_public_check(EVP_PKEY_CTX* ctx); int32_t local_EVP_PKEY_up_ref(EVP_PKEY* pkey); void local_HMAC_CTX_free(HMAC_CTX* ctx); HMAC_CTX* local_HMAC_CTX_new(void); diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/entrypoints.c b/src/libraries/Native/Unix/System.Security.Cryptography.Native/entrypoints.c index 99db84bfc3c..bf68f23be36 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/entrypoints.c +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/entrypoints.c @@ -23,7 +23,6 @@ #include "pal_hmac.h" #include "pal_ocsp.h" #include "pal_pkcs7.h" -#include "pal_rsa.h" #include "pal_ssl.h" #include "pal_x509.h" #include "pal_x509ext.h" @@ -57,7 +56,8 @@ static const Entry s_cryptoNative[] = DllImportEntry(CryptoNative_DecodeExtendedKeyUsage) DllImportEntry(CryptoNative_DecodeOcspResponse) DllImportEntry(CryptoNative_DecodePkcs7) - DllImportEntry(CryptoNative_DecodeRsaPublicKey) + DllImportEntry(CryptoNative_DecodePkcs8PrivateKey) + DllImportEntry(CryptoNative_DecodeSubjectPublicKeyInfo) DllImportEntry(CryptoNative_DecodeX509) DllImportEntry(CryptoNative_DecodeX509BasicConstraints2Extension) DllImportEntry(CryptoNative_DecodeX509Crl) @@ -84,6 +84,8 @@ static const Entry s_cryptoNative[] = DllImportEntry(CryptoNative_EncodeAsn1Integer) DllImportEntry(CryptoNative_EncodeOcspRequest) DllImportEntry(CryptoNative_EncodePkcs7) + DllImportEntry(CryptoNative_EncodePkcs8PrivateKey) + DllImportEntry(CryptoNative_EncodeSubjectPublicKeyInfo) DllImportEntry(CryptoNative_EncodeX509) DllImportEntry(CryptoNative_EncodeX509SubjectPublicKeyInfo) DllImportEntry(CryptoNative_ErrClearError) @@ -144,16 +146,16 @@ static const Entry s_cryptoNative[] = DllImportEntry(CryptoNative_EvpMdCtxDestroy) DllImportEntry(CryptoNative_EvpMdSize) DllImportEntry(CryptoNative_EvpPkeyCreate) + DllImportEntry(CryptoNative_EvpPKeyCreateRsa) DllImportEntry(CryptoNative_EvpPKeyCtxCreate) DllImportEntry(CryptoNative_EvpPKeyCtxDestroy) DllImportEntry(CryptoNative_EvpPKeyDeriveSecretAgreement) DllImportEntry(CryptoNative_EvpPkeyDestroy) + DllImportEntry(CryptoNative_EvpPKeyDuplicate) DllImportEntry(CryptoNative_EvpPkeyGetDsa) DllImportEntry(CryptoNative_EvpPkeyGetEcKey) - DllImportEntry(CryptoNative_EvpPkeyGetRsa) DllImportEntry(CryptoNative_EvpPkeySetDsa) DllImportEntry(CryptoNative_EvpPkeySetEcKey) - DllImportEntry(CryptoNative_EvpPkeySetRsa) DllImportEntry(CryptoNative_EvpPKeySize) DllImportEntry(CryptoNative_EvpRC2Cbc) DllImportEntry(CryptoNative_EvpRC2Ecb) @@ -174,8 +176,9 @@ static const Entry s_cryptoNative[] = DllImportEntry(CryptoNative_GetOcspRequestDerSize) DllImportEntry(CryptoNative_GetPkcs7Certificates) DllImportEntry(CryptoNative_GetPkcs7DerSize) + DllImportEntry(CryptoNative_GetPkcs8PrivateKeySize) DllImportEntry(CryptoNative_GetRandomBytes) - DllImportEntry(CryptoNative_GetRsaParameters) + DllImportEntry(CryptoNative_GetSubjectPublicKeyInfoSize) DllImportEntry(CryptoNative_GetX509CrlNextUpdate) DllImportEntry(CryptoNative_GetX509DerSize) DllImportEntry(CryptoNative_GetX509EkuField) @@ -227,16 +230,11 @@ static const Entry s_cryptoNative[] = DllImportEntry(CryptoNative_ReadX509AsDerFromBio) DllImportEntry(CryptoNative_RecursiveFreeX509Stack) DllImportEntry(CryptoNative_RegisterLegacyAlgorithms) - DllImportEntry(CryptoNative_RsaCreate) DllImportEntry(CryptoNative_RsaDecrypt) - DllImportEntry(CryptoNative_RsaDestroy) DllImportEntry(CryptoNative_RsaEncrypt) DllImportEntry(CryptoNative_RsaGenerateKey) DllImportEntry(CryptoNative_RsaSignHash) - DllImportEntry(CryptoNative_RsaSize) - DllImportEntry(CryptoNative_RsaUpRef) DllImportEntry(CryptoNative_RsaVerifyHash) - DllImportEntry(CryptoNative_SetRsaParameters) DllImportEntry(CryptoNative_UpRefEvpPkey) DllImportEntry(CryptoNative_X509ChainBuildOcspRequest) DllImportEntry(CryptoNative_X509ChainGetCachedOcspStatus) diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/opensslshim.h b/src/libraries/Native/Unix/System.Security.Cryptography.Native/opensslshim.h index 510d319a11d..69c95b532ad 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/opensslshim.h @@ -203,6 +203,8 @@ const EVP_CIPHER* EVP_chacha20_poly1305(void); REQUIRED_FUNCTION(d2i_PKCS12_fp) \ REQUIRED_FUNCTION(d2i_PKCS7) \ REQUIRED_FUNCTION(d2i_PKCS7_bio) \ + REQUIRED_FUNCTION(d2i_PKCS8_PRIV_KEY_INFO) \ + REQUIRED_FUNCTION(d2i_PUBKEY) \ REQUIRED_FUNCTION(d2i_RSAPublicKey) \ REQUIRED_FUNCTION(d2i_X509) \ REQUIRED_FUNCTION(d2i_X509_bio) \ @@ -319,6 +321,8 @@ const EVP_CIPHER* EVP_chacha20_poly1305(void); RENAMED_FUNCTION(EVP_MD_CTX_free, EVP_MD_CTX_destroy) \ RENAMED_FUNCTION(EVP_MD_CTX_new, EVP_MD_CTX_create) \ RENAMED_FUNCTION(EVP_MD_get_size, EVP_MD_size) \ + REQUIRED_FUNCTION(EVP_PKCS82PKEY) \ + REQUIRED_FUNCTION(EVP_PKEY2PKCS8) \ REQUIRED_FUNCTION(EVP_PKEY_CTX_ctrl) \ REQUIRED_FUNCTION(EVP_PKEY_CTX_free) \ REQUIRED_FUNCTION(EVP_PKEY_CTX_get0_pkey) \ @@ -329,6 +333,7 @@ const EVP_CIPHER* EVP_chacha20_poly1305(void); FALLBACK_FUNCTION(EVP_PKEY_CTX_set_rsa_padding) \ FALLBACK_FUNCTION(EVP_PKEY_CTX_set_rsa_pss_saltlen) \ FALLBACK_FUNCTION(EVP_PKEY_CTX_set_signature_md) \ + FALLBACK_FUNCTION(EVP_PKEY_check) \ REQUIRED_FUNCTION(EVP_PKEY_decrypt) \ REQUIRED_FUNCTION(EVP_PKEY_decrypt_init) \ REQUIRED_FUNCTION(EVP_PKEY_derive_set_peer) \ @@ -346,6 +351,7 @@ const EVP_CIPHER* EVP_chacha20_poly1305(void); REQUIRED_FUNCTION(EVP_PKEY_keygen) \ REQUIRED_FUNCTION(EVP_PKEY_keygen_init) \ REQUIRED_FUNCTION(EVP_PKEY_new) \ + FALLBACK_FUNCTION(EVP_PKEY_public_check) \ REQUIRED_FUNCTION(EVP_PKEY_set1_DSA) \ REQUIRED_FUNCTION(EVP_PKEY_set1_EC_KEY) \ REQUIRED_FUNCTION(EVP_PKEY_set1_RSA) \ @@ -376,6 +382,8 @@ const EVP_CIPHER* EVP_chacha20_poly1305(void); REQUIRED_FUNCTION(i2d_OCSP_REQUEST) \ REQUIRED_FUNCTION(i2d_OCSP_RESPONSE) \ REQUIRED_FUNCTION(i2d_PKCS7) \ + REQUIRED_FUNCTION(i2d_PKCS8_PRIV_KEY_INFO) \ + REQUIRED_FUNCTION(i2d_PUBKEY) \ REQUIRED_FUNCTION(i2d_X509) \ REQUIRED_FUNCTION(i2d_X509_PUBKEY) \ REQUIRED_FUNCTION(OBJ_ln2nid) \ @@ -412,6 +420,7 @@ const EVP_CIPHER* EVP_chacha20_poly1305(void); RENAMED_FUNCTION(OPENSSL_sk_value, sk_value) \ FALLBACK_FUNCTION(OpenSSL_version_num) \ LIGHTUP_FUNCTION(OSSL_PROVIDER_try_load) \ + REQUIRED_FUNCTION(PKCS8_PRIV_KEY_INFO_free) \ REQUIRED_FUNCTION(PEM_read_bio_PKCS7) \ REQUIRED_FUNCTION(PEM_read_bio_X509) \ REQUIRED_FUNCTION(PEM_read_bio_X509_AUX) \ @@ -642,6 +651,8 @@ FOR_ALL_OPENSSL_FUNCTIONS #define d2i_PKCS12_fp d2i_PKCS12_fp_ptr #define d2i_PKCS7 d2i_PKCS7_ptr #define d2i_PKCS7_bio d2i_PKCS7_bio_ptr +#define d2i_PKCS8_PRIV_KEY_INFO d2i_PKCS8_PRIV_KEY_INFO_ptr +#define d2i_PUBKEY d2i_PUBKEY_ptr #define d2i_RSAPublicKey d2i_RSAPublicKey_ptr #define d2i_X509 d2i_X509_ptr #define d2i_X509_bio d2i_X509_bio_ptr @@ -758,6 +769,8 @@ FOR_ALL_OPENSSL_FUNCTIONS #define EVP_MD_CTX_free EVP_MD_CTX_free_ptr #define EVP_MD_CTX_new EVP_MD_CTX_new_ptr #define EVP_MD_get_size EVP_MD_get_size_ptr +#define EVP_PKCS82PKEY EVP_PKCS82PKEY_ptr +#define EVP_PKEY2PKCS8 EVP_PKEY2PKCS8_ptr #define EVP_PKEY_CTX_ctrl EVP_PKEY_CTX_ctrl_ptr #define EVP_PKEY_CTX_free EVP_PKEY_CTX_free_ptr #define EVP_PKEY_CTX_get0_pkey EVP_PKEY_CTX_get0_pkey_ptr @@ -768,6 +781,7 @@ FOR_ALL_OPENSSL_FUNCTIONS #define EVP_PKEY_CTX_set_rsa_padding EVP_PKEY_CTX_set_rsa_padding_ptr #define EVP_PKEY_CTX_set_rsa_pss_saltlen EVP_PKEY_CTX_set_rsa_pss_saltlen_ptr #define EVP_PKEY_CTX_set_signature_md EVP_PKEY_CTX_set_signature_md_ptr +#define EVP_PKEY_check EVP_PKEY_check_ptr #define EVP_PKEY_decrypt_init EVP_PKEY_decrypt_init_ptr #define EVP_PKEY_decrypt EVP_PKEY_decrypt_ptr #define EVP_PKEY_derive_set_peer EVP_PKEY_derive_set_peer_ptr @@ -785,6 +799,7 @@ FOR_ALL_OPENSSL_FUNCTIONS #define EVP_PKEY_keygen EVP_PKEY_keygen_ptr #define EVP_PKEY_keygen_init EVP_PKEY_keygen_init_ptr #define EVP_PKEY_new EVP_PKEY_new_ptr +#define EVP_PKEY_public_check EVP_PKEY_public_check_ptr #define EVP_PKEY_set1_DSA EVP_PKEY_set1_DSA_ptr #define EVP_PKEY_set1_EC_KEY EVP_PKEY_set1_EC_KEY_ptr #define EVP_PKEY_set1_RSA EVP_PKEY_set1_RSA_ptr @@ -815,6 +830,8 @@ FOR_ALL_OPENSSL_FUNCTIONS #define i2d_OCSP_REQUEST i2d_OCSP_REQUEST_ptr #define i2d_OCSP_RESPONSE i2d_OCSP_RESPONSE_ptr #define i2d_PKCS7 i2d_PKCS7_ptr +#define i2d_PKCS8_PRIV_KEY_INFO i2d_PKCS8_PRIV_KEY_INFO_ptr +#define i2d_PUBKEY i2d_PUBKEY_ptr #define i2d_X509 i2d_X509_ptr #define i2d_X509_PUBKEY i2d_X509_PUBKEY_ptr #define OBJ_ln2nid OBJ_ln2nid_ptr @@ -851,6 +868,7 @@ FOR_ALL_OPENSSL_FUNCTIONS #define OPENSSL_sk_value OPENSSL_sk_value_ptr #define OpenSSL_version_num OpenSSL_version_num_ptr #define OSSL_PROVIDER_try_load OSSL_PROVIDER_try_load_ptr +#define PKCS8_PRIV_KEY_INFO_free PKCS8_PRIV_KEY_INFO_free_ptr #define PEM_read_bio_PKCS7 PEM_read_bio_PKCS7_ptr #define PEM_read_bio_X509 PEM_read_bio_X509_ptr #define PEM_read_bio_X509_AUX PEM_read_bio_X509_AUX_ptr @@ -1109,7 +1127,9 @@ FOR_ALL_OPENSSL_FUNCTIONS #define EVP_CIPHER_CTX_free local_EVP_CIPHER_CTX_free #define EVP_CIPHER_CTX_new local_EVP_CIPHER_CTX_new #define EVP_CIPHER_CTX_reset local_EVP_CIPHER_CTX_reset +#define EVP_PKEY_check local_EVP_PKEY_check #define EVP_PKEY_get0_RSA local_EVP_PKEY_get0_RSA +#define EVP_PKEY_public_check local_EVP_PKEY_public_check #define EVP_PKEY_up_ref local_EVP_PKEY_up_ref #define HMAC_CTX_free local_HMAC_CTX_free #define HMAC_CTX_new local_HMAC_CTX_new diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/osslcompat_111.h b/src/libraries/Native/Unix/System.Security.Cryptography.Native/osslcompat_111.h index 6791e306019..59f0fc5f59d 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/osslcompat_111.h +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/osslcompat_111.h @@ -31,6 +31,8 @@ int32_t EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX* ctx); void EVP_MD_CTX_free(EVP_MD_CTX* ctx); EVP_MD_CTX* EVP_MD_CTX_new(void); RSA* EVP_PKEY_get0_RSA(EVP_PKEY* pkey); +int EVP_PKEY_check(EVP_PKEY_CTX* ctx); +int EVP_PKEY_public_check(EVP_PKEY_CTX* ctx); int32_t EVP_PKEY_up_ref(EVP_PKEY* pkey); void HMAC_CTX_free(HMAC_CTX* ctx); HMAC_CTX* HMAC_CTX_new(void); diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.c b/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.c index a9fd4b2acd5..6839d4c2fe0 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.c +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.c @@ -9,6 +9,54 @@ EVP_PKEY* CryptoNative_EvpPkeyCreate() return EVP_PKEY_new(); } +EVP_PKEY* CryptoNative_EvpPKeyDuplicate(EVP_PKEY* currentKey, int32_t algId) +{ + assert(currentKey != NULL); + + int currentAlgId = EVP_PKEY_get_base_id(currentKey); + + if (algId != NID_undef && algId != currentAlgId) + { + ERR_put_error(ERR_LIB_EVP, 0, EVP_R_DIFFERENT_KEY_TYPES, __FILE__, __LINE__); + return NULL; + } + + EVP_PKEY* newKey = EVP_PKEY_new(); + + if (newKey == NULL) + { + return NULL; + } + + bool success = true; + + if (currentAlgId == EVP_PKEY_RSA) + { + const RSA* rsa = EVP_PKEY_get0_RSA(currentKey); + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcast-qual" + if (rsa == NULL || !EVP_PKEY_set1_RSA(newKey, (RSA*)rsa)) +#pragma clang diagnostic pop + { + success = false; + } + } + else + { + ERR_put_error(ERR_LIB_EVP, 0, EVP_R_UNSUPPORTED_ALGORITHM, __FILE__, __LINE__); + success = false; + } + + if (!success) + { + EVP_PKEY_free(newKey); + newKey = NULL; + } + + return newKey; +} + void CryptoNative_EvpPkeyDestroy(EVP_PKEY* pkey) { if (pkey != NULL) @@ -32,3 +80,122 @@ int32_t CryptoNative_UpRefEvpPkey(EVP_PKEY* pkey) return EVP_PKEY_up_ref(pkey); } + +static bool CheckKey(EVP_PKEY* key, int32_t algId, int32_t (*check_func)(EVP_PKEY_CTX*)) +{ + if (algId != NID_undef && EVP_PKEY_get_base_id(key) != algId) + { + ERR_put_error(ERR_LIB_EVP, 0, EVP_R_UNSUPPORTED_ALGORITHM, __FILE__, __LINE__); + return false; + } + + EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(key, NULL); + + if (ctx == NULL) + { + // The malloc error should have already been set. + return false; + } + + int check = check_func(ctx); + EVP_PKEY_CTX_free(ctx); + + // 1: Success + // -2: The key object had no check routine available. + if (check == 1 || check == -2) + { + // We need to clear for -2, doesn't hurt for 1. + ERR_clear_error(); + return true; + } + + return false; +} + +EVP_PKEY* CryptoNative_DecodeSubjectPublicKeyInfo(const uint8_t* buf, int32_t len, int32_t algId) +{ + assert(buf != NULL); + assert(len > 0); + + EVP_PKEY* key = d2i_PUBKEY(NULL, &buf, len); + + if (key != NULL && !CheckKey(key, algId, EVP_PKEY_public_check)) + { + EVP_PKEY_free(key); + key = NULL; + } + + return key; +} + +EVP_PKEY* CryptoNative_DecodePkcs8PrivateKey(const uint8_t* buf, int32_t len, int32_t algId) +{ + assert(buf != NULL); + assert(len > 0); + + PKCS8_PRIV_KEY_INFO* p8info = d2i_PKCS8_PRIV_KEY_INFO(NULL, &buf, len); + + if (p8info == NULL) + { + return NULL; + } + + EVP_PKEY* key = EVP_PKCS82PKEY(p8info); + PKCS8_PRIV_KEY_INFO_free(p8info); + + if (key != NULL && !CheckKey(key, algId, EVP_PKEY_check)) + { + EVP_PKEY_free(key); + key = NULL; + } + + return key; +} + +int32_t CryptoNative_GetPkcs8PrivateKeySize(EVP_PKEY* pkey) +{ + assert(pkey != NULL); + + PKCS8_PRIV_KEY_INFO* p8 = EVP_PKEY2PKCS8(pkey); + + if (p8 == NULL) + { + return -1; + } + + int ret = i2d_PKCS8_PRIV_KEY_INFO(p8, NULL); + PKCS8_PRIV_KEY_INFO_free(p8); + return ret; +} + +int32_t CryptoNative_EncodePkcs8PrivateKey(EVP_PKEY* pkey, uint8_t* buf) +{ + assert(pkey != NULL); + assert(buf != NULL); + + PKCS8_PRIV_KEY_INFO* p8 = EVP_PKEY2PKCS8(pkey); + + if (p8 == NULL) + { + return -1; + } + + int ret = i2d_PKCS8_PRIV_KEY_INFO(p8, &buf); + PKCS8_PRIV_KEY_INFO_free(p8); + return ret; +} + +int32_t CryptoNative_GetSubjectPublicKeyInfoSize(EVP_PKEY* pkey) +{ + assert(pkey != NULL); + + return i2d_PUBKEY(pkey, NULL); +} + +int32_t CryptoNative_EncodeSubjectPublicKeyInfo(EVP_PKEY* pkey, uint8_t* buf) +{ + assert(pkey != NULL); + assert(buf != NULL); + + return i2d_PUBKEY(pkey, &buf); +} diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.h b/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.h index 98139a8c417..012ac98e03d 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.h +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.h @@ -13,6 +13,12 @@ Returns the new EVP_PKEY instance. PALEXPORT EVP_PKEY* CryptoNative_EvpPkeyCreate(void); /* +Create a new EVP_PKEY that has the same interior key as currentKey, +optionally verifying that the key has the correct algorithm. +*/ +PALEXPORT EVP_PKEY* CryptoNative_EvpPKeyDuplicate(EVP_PKEY* currentKey, int32_t algId); + +/* Cleans up and deletes a EVP_PKEY instance. Implemented by calling EVP_PKEY_free. @@ -36,3 +42,45 @@ Returns the number (as of this call) of references to the EVP_PKEY. Anything les 2 is an error, because the key is already in the process of being freed. */ PALEXPORT int32_t CryptoNative_UpRefEvpPkey(EVP_PKEY* pkey); + +/* +Decodes an X.509 SubjectPublicKeyInfo into an EVP_PKEY*, verifying the interpreted algorithm type. + +Requres a non-null buf, and len > 0. +*/ +PALEXPORT EVP_PKEY* CryptoNative_DecodeSubjectPublicKeyInfo(const uint8_t* buf, int32_t len, int32_t algId); + +/* +Decodes an Pkcs8PrivateKeyInfo into an EVP_PKEY*, verifying the interpreted algorithm type. + +Requres a non-null buf, and len > 0. +*/ +PALEXPORT EVP_PKEY* CryptoNative_DecodePkcs8PrivateKey(const uint8_t* buf, int32_t len, int32_t algId); + +/* +Reports the number of bytes rqeuired to encode an EVP_PKEY* as a Pkcs8PrivateKeyInfo, or a negative value on error. +*/ +PALEXPORT int32_t CryptoNative_GetPkcs8PrivateKeySize(EVP_PKEY* pkey); + +/* +Encodes the EVP_PKEY* as a Pkcs8PrivateKeyInfo, writing the encoded value to buf. + +buf must be big enough, or an out of bounds write may occur. + +Returns the number of bytes written. +*/ +PALEXPORT int32_t CryptoNative_EncodePkcs8PrivateKey(EVP_PKEY* pkey, uint8_t* buf); + +/* +Reports the number of bytes rqeuired to encode an EVP_PKEY* as an X.509 SubjectPublicKeyInfo, or a negative value on error. +*/ +PALEXPORT int32_t CryptoNative_GetSubjectPublicKeyInfoSize(EVP_PKEY* pkey); + +/* +Encodes the EVP_PKEY* as an X.509 SubjectPublicKeyInfo, writing the encoded value to buf. + +buf must be big enough, or an out of bounds write may occur. + +Returns the number of bytes written. +*/ +PALEXPORT int32_t CryptoNative_EncodeSubjectPublicKeyInfo(EVP_PKEY* pkey, uint8_t* buf); diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c b/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c index 0efe651cfe8..36924abb505 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c @@ -7,6 +7,26 @@ static int HasNoPrivateKey(const RSA* rsa); +EVP_PKEY* CryptoNative_EvpPKeyCreateRsa(RSA* currentKey) +{ + assert(currentKey != NULL); + + EVP_PKEY* pkey = EVP_PKEY_new(); + + if (pkey == NULL) + { + return NULL; + } + + if (!EVP_PKEY_set1_RSA(pkey, currentKey)) + { + EVP_PKEY_free(pkey); + return NULL; + } + + return pkey; +} + EVP_PKEY* CryptoNative_RsaGenerateKey(int keySize) { EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); @@ -294,16 +314,6 @@ done: return ret; } -RSA* CryptoNative_EvpPkeyGetRsa(EVP_PKEY* pkey) -{ - return EVP_PKEY_get1_RSA(pkey); -} - -int32_t CryptoNative_EvpPkeySetRsa(EVP_PKEY* pkey, RSA* rsa) -{ - return EVP_PKEY_set1_RSA(pkey, rsa); -} - static int HasNoPrivateKey(const RSA* rsa) { if (rsa == NULL) diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h b/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h index d913bc3554b..2d3c5878765 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h @@ -16,6 +16,11 @@ typedef enum } RsaPaddingMode; /* +Create a new EVP_PKEY* wrapping an existing RSA key. +*/ +PALEXPORT EVP_PKEY* CryptoNative_EvpPKeyCreateRsa(RSA* currentKey); + +/* Creates an RSA key of the requested size. */ PALEXPORT EVP_PKEY* CryptoNative_RsaGenerateKey(int32_t keySize); @@ -74,17 +79,3 @@ PALEXPORT int32_t CryptoNative_RsaVerifyHash(EVP_PKEY* pkey, const uint8_t* signature, int32_t signatureLen); -/* -Shims the EVP_PKEY_get1_RSA method. - -Returns the RSA instance for the EVP_PKEY. -*/ -PALEXPORT RSA* CryptoNative_EvpPkeyGetRsa(EVP_PKEY* pkey); - -/* -Shims the EVP_PKEY_set1_RSA method to set the RSA -instance on the EVP_KEY. - -Returns 1 upon success, otherwise 0. -*/ -PALEXPORT int32_t CryptoNative_EvpPkeySetRsa(EVP_PKEY* pkey, RSA* rsa); diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_rsa.c b/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_rsa.c deleted file mode 100644 index 197f8bfd9bb..00000000000 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_rsa.c +++ /dev/null @@ -1,249 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "pal_rsa.h" -#include "pal_utilities.h" - -RSA* CryptoNative_RsaCreate() -{ - return RSA_new(); -} - -int32_t CryptoNative_RsaUpRef(RSA* rsa) -{ - return RSA_up_ref(rsa); -} - -void CryptoNative_RsaDestroy(RSA* rsa) -{ - if (rsa != NULL) - { - RSA_free(rsa); - } -} - -RSA* CryptoNative_DecodeRsaPublicKey(const uint8_t* buf, int32_t len) -{ - if (!buf || !len) - { - return NULL; - } - - return d2i_RSAPublicKey(NULL, &buf, len); -} - -int32_t CryptoNative_RsaSize(RSA* rsa) -{ - return RSA_size(rsa); -} - -int32_t CryptoNative_GetRsaParameters(const RSA* rsa, - const BIGNUM** n, - const BIGNUM** e, - const BIGNUM** d, - const BIGNUM** p, - const BIGNUM** dmp1, - const BIGNUM** q, - const BIGNUM** dmq1, - const BIGNUM** iqmp) -{ - if (!rsa || !n || !e || !d || !p || !dmp1 || !q || !dmq1 || !iqmp) - { - assert(false); - - // since these parameters are 'out' parameters in managed code, ensure they are initialized - if (n) - *n = NULL; - if (e) - *e = NULL; - if (d) - *d = NULL; - if (p) - *p = NULL; - if (dmp1) - *dmp1 = NULL; - if (q) - *q = NULL; - if (dmq1) - *dmq1 = NULL; - if (iqmp) - *iqmp = NULL; - - return 0; - } - - RSA_get0_key(rsa, n, e, d); - RSA_get0_factors(rsa, p, q); - RSA_get0_crt_params(rsa, dmp1, dmq1, iqmp); - - return 1; -} - -static BIGNUM* MakeBignum(uint8_t* buffer, int32_t bufferLength) -{ - if (buffer && bufferLength) - { - return BN_bin2bn(buffer, bufferLength, NULL); - } - - return NULL; -} - -static int32_t ValidatePrivateRsaParameters(BIGNUM* bnN, - BIGNUM* bnE, - BIGNUM* bnD, - BIGNUM* bnP, - BIGNUM* bnQ, - BIGNUM* bnDmp1, - BIGNUM* bnDmq1, - BIGNUM* bnIqmp) -{ - if (!bnN || !bnE || !bnD || !bnP || !bnQ || - !bnDmp1 || !bnDmq1 || !bnIqmp) - { - assert(false); - return 0; - } - - // This is shared and should not be freed. - const RSA_METHOD* openssl_method = RSA_PKCS1_OpenSSL(); - - RSA* rsa = RSA_new(); - - if (!rsa) - { - return 0; - } - - // RSA_check_key only works when it has access to the - // internal values of the RSA*. If the process - // has changed the default ENGINE, the function - // may fail. For purposes of validation, we always - // do it using the openssl methods. - if (!RSA_set_method(rsa, openssl_method)) - { - RSA_free(rsa); - return 0; - } - - BIGNUM* bnNdup = BN_dup(bnN); - BIGNUM* bnEdup = BN_dup(bnE); - BIGNUM* bnDdup = BN_dup(bnD); - - if (!RSA_set0_key(rsa, bnNdup, bnEdup, bnDdup)) - { - BN_free(bnNdup); - BN_free(bnEdup); - BN_clear_free(bnDdup); - RSA_free(rsa); - return 0; - } - - BIGNUM* bnPdup = BN_dup(bnP); - BIGNUM* bnQdup = BN_dup(bnQ); - - if (!RSA_set0_factors(rsa, bnPdup, bnQdup)) - { - BN_clear_free(bnPdup); - BN_clear_free(bnQdup); - RSA_free(rsa); - return 0; - } - - BIGNUM* bnDmp1dup = BN_dup(bnDmp1); - BIGNUM* bnDmq1dup = BN_dup(bnDmq1); - BIGNUM* bnIqmpdup = BN_dup(bnIqmp); - - if (!RSA_set0_crt_params(rsa, bnDmp1dup, bnDmq1dup, bnIqmpdup)) - { - BN_clear_free(bnDmp1dup); - BN_clear_free(bnDmq1dup); - BN_clear_free(bnIqmpdup); - RSA_free(rsa); - return 0; - } - - if (RSA_check_key(rsa) != 1) - { - RSA_free(rsa); - return 0; - } - - RSA_free(rsa); - return 1; -} - -int32_t CryptoNative_SetRsaParameters(RSA* rsa, - uint8_t* n, - int32_t nLength, - uint8_t* e, - int32_t eLength, - uint8_t* d, - int32_t dLength, - uint8_t* p, - int32_t pLength, - uint8_t* dmp1, - int32_t dmp1Length, - uint8_t* q, - int32_t qLength, - uint8_t* dmq1, - int32_t dmq1Length, - uint8_t* iqmp, - int32_t iqmpLength) -{ - if (!rsa) - { - assert(false); - return 0; - } - - BIGNUM* bnN = MakeBignum(n, nLength); - BIGNUM* bnE = MakeBignum(e, eLength); - BIGNUM* bnD = MakeBignum(d, dLength); - - if (!RSA_set0_key(rsa, bnN, bnE, bnD)) - { - // BN_free handles NULL input - BN_free(bnN); - BN_free(bnE); - BN_free(bnD); - return 0; - } - - if (bnD != NULL) - { - BIGNUM* bnP = MakeBignum(p, pLength); - BIGNUM* bnQ = MakeBignum(q, qLength); - BIGNUM* bnDmp1 = MakeBignum(dmp1, dmp1Length); - BIGNUM* bnDmq1 = MakeBignum(dmq1, dmq1Length); - BIGNUM* bnIqmp = MakeBignum(iqmp, iqmpLength); - - if (!ValidatePrivateRsaParameters(bnN, - bnE, - bnD, - bnP, - bnQ, - bnDmp1, - bnDmq1, - bnIqmp) - || !RSA_set0_factors(rsa, bnP, bnQ)) - { - BN_free(bnP); - BN_free(bnQ); - BN_free(bnDmp1); - BN_free(bnDmq1); - BN_free(bnIqmp); - return 0; - } - - if (!RSA_set0_crt_params(rsa, bnDmp1, bnDmq1, bnIqmp)) - { - BN_free(bnDmp1); - BN_free(bnDmq1); - BN_free(bnIqmp); - return 0; - } - } - - return 1; -} diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_rsa.h b/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_rsa.h deleted file mode 100644 index bebcaa34439..00000000000 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_rsa.h +++ /dev/null @@ -1,79 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "pal_types.h" -#include "pal_compiler.h" -#include "opensslshim.h" - -/* -Shims the RSA_new method. - -Returns the new RSA instance. -*/ -PALEXPORT RSA* CryptoNative_RsaCreate(void); - -/* -Shims the RSA_up_ref method. - -Returns 1 upon success, otherwise 0. -*/ -PALEXPORT int32_t CryptoNative_RsaUpRef(RSA* rsa); - -/* -Cleans up and deletes a RSA instance. - -Implemented by calling RSA_free - -No-op if rsa is null. -The given RSA pointer is invalid after this call. -Always succeeds. -*/ -PALEXPORT void CryptoNative_RsaDestroy(RSA* rsa); - -/* -Shims the d2i_RSAPublicKey method and makes it easier to invoke from managed code. -*/ -PALEXPORT RSA* CryptoNative_DecodeRsaPublicKey(const uint8_t* buf, int32_t len); - -/* -Shims the RSA_size method. - -Returns the RSA modulus size in bytes. -*/ -PALEXPORT int32_t CryptoNative_RsaSize(RSA* rsa); - -/* -Gets all the parameters from the RSA instance. - -Returns 1 upon success, otherwise 0. -*/ -PALEXPORT int32_t CryptoNative_GetRsaParameters(const RSA* rsa, - const BIGNUM** n, - const BIGNUM** e, - const BIGNUM** d, - const BIGNUM** p, - const BIGNUM** dmp1, - const BIGNUM** q, - const BIGNUM** dmq1, - const BIGNUM** iqmp); - -/* -Sets all the parameters on the RSA instance. -*/ -PALEXPORT int32_t CryptoNative_SetRsaParameters(RSA* rsa, - uint8_t* n, - int32_t nLength, - uint8_t* e, - int32_t eLength, - uint8_t* d, - int32_t dLength, - uint8_t* p, - int32_t pLength, - uint8_t* dmp1, - int32_t dmp1Length, - uint8_t* q, - int32_t qLength, - uint8_t* dmq1, - int32_t dmq1Length, - uint8_t* iqmp, - int32_t iqmpLength); diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_ssl.c b/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_ssl.c index acdc977b5f3..77ac385a799 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_ssl.c +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_ssl.c @@ -5,7 +5,6 @@ #include "openssl.h" #include "pal_evp_pkey.h" #include "pal_evp_pkey_rsa.h" -#include "pal_rsa.h" #include "pal_x509.h" #include <assert.h> @@ -689,7 +688,7 @@ static int MakeSelfSignedCertificate(X509 * cert, EVP_PKEY* evp) if (rsa != NULL) { - if (CryptoNative_EvpPkeySetRsa(evp, rsa) == 1) + if (EVP_PKEY_set1_RSA(evp, rsa) == 1) { rsa = NULL; } diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj b/src/libraries/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj index fd8d0a8b88b..754b2e38861 100644 --- a/src/libraries/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj +++ b/src/libraries/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj @@ -6,14 +6,14 @@ <TargetFrameworks>$(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-Unix;$(NetCoreAppCurrent)-Android;$(NetCoreAppCurrent)-OSX;$(NetCoreAppCurrent)-iOS;$(NetCoreAppCurrent)-tvOS;$(NetCoreAppCurrent)-Browser</TargetFrameworks> <Nullable>enable</Nullable> </PropertyGroup> - <Import Project="$(CommonPath)System\Security\Cryptography\Asn1\AsnXml.targets" /> - <Import Project="$(CommonPath)System\Security\Cryptography\Asn1Reader\System.Security.Cryptography.Asn1Reader.Shared.projitems" /> <PropertyGroup> <UseAndroidCrypto Condition="'$(TargetsAndroid)' == 'true'">true</UseAndroidCrypto> <UseAppleCrypto Condition="'$(TargetsOSX)' == 'true' or '$(TargetsiOS)' == 'true' or '$(TargetstvOS)' == 'true'">true</UseAppleCrypto> <GeneratePlatformNotSupportedAssemblyMessage Condition="'$(TargetsBrowser)' == 'true'">SR.SystemSecurityCryptographyAlgorithms_PlatformNotSupported</GeneratePlatformNotSupportedAssemblyMessage> <ApiExclusionListPath Condition="'$(TargetsBrowser)' == 'true'">ExcludeApiList.PNSE.Browser.txt</ApiExclusionListPath> </PropertyGroup> + <Import Project="$(CommonPath)System\Security\Cryptography\Asn1\AsnXml.targets" Condition="'$(GeneratePlatformNotSupportedAssemblyMessage)' == ''"/> + <Import Project="$(CommonPath)System\Security\Cryptography\Asn1Reader\System.Security.Cryptography.Asn1Reader.Shared.projitems" Condition="'$(GeneratePlatformNotSupportedAssemblyMessage)' == ''" /> <ItemGroup> <Compile Include="System\Security\Cryptography\CryptoConfig.Common.cs" /> <Compile Include="Internal\Cryptography\HashAlgorithmNames.cs" /> @@ -130,6 +130,8 @@ Link="Common\System\Security\Cryptography\HashOneShotHelpers.cs" /> <Compile Include="$(CommonPath)System\Security\Cryptography\KeyFormatHelper.cs" Link="Common\System\Security\Cryptography\KeyFormatHelper.cs" /> + <Compile Include="$(CommonPath)System\Security\Cryptography\KeyFormatHelper.Encrypted.cs" + Link="Common\System\Security\Cryptography\KeyFormatHelper.Encrypted.cs" /> <Compile Include="$(CommonPath)System\Security\Cryptography\KeySizeHelpers.cs" Link="Common\System\Security\Cryptography\KeySizeHelpers.cs" /> <Compile Include="$(CommonPath)System\Security\Cryptography\Oids.cs" @@ -144,6 +146,8 @@ Link="Common\System\Security\Cryptography\Pkcs12Kdf.cs" /> <Compile Include="$(CommonPath)System\Security\Cryptography\RSAKeyFormatHelper.cs" Link="Common\System\Security\Cryptography\RSAKeyFormatHelper.cs" /> + <Compile Include="$(CommonPath)System\Security\Cryptography\RSAKeyFormatHelper.Encrypted.cs" + Link="Common\System\Security\Cryptography\RSAKeyFormatHelper.Encrypted.cs" /> <Compile Include="$(CommonPath)System\Security\Cryptography\RsaPaddingProcessor.cs" Link="Common\System\Security\Cryptography\RsaPaddingProcessor.cs" /> <AsnXml Include="$(CommonPath)System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml"> @@ -629,10 +633,6 @@ Link="Common\System\Security\Cryptography\ECDiffieHellmanOpenSsl.Derive.cs" /> <Compile Include="$(CommonPath)System\Security\Cryptography\ECDiffieHellmanOpenSslPublicKey.cs" Link="Common\System\Security\Cryptography\ECDiffieHellmanOpenSslPublicKey.cs" /> - <Compile Include="$(CommonPath)Interop\Unix\System.Security.Cryptography.Native\Interop.Rsa.cs" - Link="Common\Interop\Unix\System.Security.Cryptography.Native\Interop.Rsa.cs" /> - <Compile Include="$(CommonPath)Microsoft\Win32\SafeHandles\SafeRsaHandle.Unix.cs" - Link="Common\Microsoft\Win32\SafeHandles\SafeRsaHandle.Unix.cs" /> <Compile Include="$(CommonPath)System\Security\Cryptography\RSAOpenSsl.cs" Link="Common\System\Security\Cryptography\RSAOpenSsl.cs" /> <Compile Include="Internal\Cryptography\RC2Implementation.Unix.cs" /> diff --git a/src/libraries/System.Security.Cryptography.Cng/src/System.Security.Cryptography.Cng.csproj b/src/libraries/System.Security.Cryptography.Cng/src/System.Security.Cryptography.Cng.csproj index b4d0c91a2d2..fb654f6698b 100644 --- a/src/libraries/System.Security.Cryptography.Cng/src/System.Security.Cryptography.Cng.csproj +++ b/src/libraries/System.Security.Cryptography.Cng/src/System.Security.Cryptography.Cng.csproj @@ -210,6 +210,8 @@ Link="Common\System\Security\Cryptography\KeyBlobHelpers.cs" /> <Compile Include="$(CommonPath)System\Security\Cryptography\KeyFormatHelper.cs" Link="Common\System\Security\Cryptography\KeyFormatHelper.cs" /> + <Compile Include="$(CommonPath)System\Security\Cryptography\KeyFormatHelper.Encrypted.cs" + Link="Common\System\Security\Cryptography\KeyFormatHelper.Encrypted.cs" /> <Compile Include="$(CommonPath)System\Security\Cryptography\KeySizeHelpers.cs" Link="Common\System\Security\Cryptography\KeySizeHelpers.cs" /> <Compile Include="$(CommonPath)System\Security\Cryptography\Oids.cs" diff --git a/src/libraries/System.Security.Cryptography.OpenSsl/src/Resources/Strings.resx b/src/libraries/System.Security.Cryptography.OpenSsl/src/Resources/Strings.resx index 8091178afc3..40e6dcd3b22 100644 --- a/src/libraries/System.Security.Cryptography.OpenSsl/src/Resources/Strings.resx +++ b/src/libraries/System.Security.Cryptography.OpenSsl/src/Resources/Strings.resx @@ -173,9 +173,18 @@ <data name="Cryptography_InvalidPaddingMode" xml:space="preserve"> <value>Specified padding mode is not valid for this algorithm.</value> </data> + <data name="Cryptography_InvalidRsaParameters" xml:space="preserve"> + <value>The specified RSA parameters are not valid. Exponent and Modulus are required. If D is present, it must have the same length as Modulus. If D is present, P, Q, DP, DQ, and InverseQ are required and must have half the length of Modulus, rounded up, otherwise they must be omitted.</value> + </data> + <data name="Cryptography_NotValidPrivateKey" xml:space="preserve"> + <value>Key is not a valid private key.</value> + </data> <data name="Cryptography_OpenInvalidHandle" xml:space="preserve"> <value>Cannot open an invalid handle.</value> </data> + <data name="Cryptography_RSAPrivateKey_VersionTooNew" xml:space="preserve"> + <value>The provided RSAPrivateKey value has version '{0}', but version '{1}' is the maximum supported.</value> + </data> <data name="Cryptography_TlsRequires64ByteSeed" xml:space="preserve"> <value>The TLS key derivation function requires a seed value of exactly 64 bytes.</value> </data> diff --git a/src/libraries/System.Security.Cryptography.OpenSsl/src/System.Security.Cryptography.OpenSsl.csproj b/src/libraries/System.Security.Cryptography.OpenSsl/src/System.Security.Cryptography.OpenSsl.csproj index 133c02e87c4..f28aa959878 100644 --- a/src/libraries/System.Security.Cryptography.OpenSsl/src/System.Security.Cryptography.OpenSsl.csproj +++ b/src/libraries/System.Security.Cryptography.OpenSsl/src/System.Security.Cryptography.OpenSsl.csproj @@ -8,6 +8,7 @@ <GeneratePlatformNotSupportedAssemblyMessage>SR.PlatformNotSupported_CryptographyOpenSSL</GeneratePlatformNotSupportedAssemblyMessage> <UnsupportedPlatformTarget>true</UnsupportedPlatformTarget> </PropertyGroup> + <Import Project="$(CommonPath)System\Security\Cryptography\Asn1\AsnXml.targets" Condition="'$(UnsupportedPlatformTarget)' != 'true'" /> <Import Project="$(CommonPath)System\Security\Cryptography\Asn1Reader\System.Security.Cryptography.Asn1Reader.Shared.projitems" Condition="'$(UnsupportedPlatformTarget)' != 'true'" /> <ItemGroup Condition="'$(UnsupportedPlatformTarget)' != 'true'"> <Compile Include="System\Security\Cryptography\DSAOpenSsl.cs" /> @@ -54,8 +55,6 @@ Link="Common\Interop\Unix\System.Security.Cryptography.Native\Interop.Initialization.cs" /> <Compile Include="$(CommonPath)Interop\Unix\System.Security.Cryptography.Native\Interop.OpenSslVersion.cs" Link="Common\Interop\Unix\System.Security.Cryptography.Native\Interop.OpenSslVersion.cs" /> - <Compile Include="$(CommonPath)Interop\Unix\System.Security.Cryptography.Native\Interop.Rsa.cs" - Link="Common\Interop\Unix\System.Security.Cryptography.Native\Interop.Rsa.cs" /> <Compile Include="$(CommonPath)Microsoft\Win32\SafeHandles\Asn1SafeHandles.Unix.cs" Link="Common\Microsoft\Win32\SafeHandles\Asn1SafeHandles.Unix.cs" /> <Compile Include="$(CommonPath)Microsoft\Win32\SafeHandles\SafeBignumHandle.Unix.cs" @@ -64,8 +63,6 @@ Link="Common\Microsoft\Win32\SafeHandles\SafeDsaHandle.Unix.cs" /> <Compile Include="$(CommonPath)Microsoft\Win32\SafeHandles\SafeInteriorHandle.cs" Link="Common\Microsoft\Win32\SafeHandles\SafeInteriorHandle.cs" /> - <Compile Include="$(CommonPath)Microsoft\Win32\SafeHandles\SafeRsaHandle.Unix.cs" - Link="Common\Microsoft\Win32\SafeHandles\SafeRsaHandle.Unix.cs" /> <Compile Include="$(CommonPath)Microsoft\Win32\SafeHandles\SafeEcKeyHandle.Unix.cs" Link="Common\Microsoft\Win32\SafeHandles\SafeEcKeyHandle.Unix.cs" /> <Compile Include="$(CommonPath)Microsoft\Win32\SafeHandles\SafeEvpPkeyCtxHandle.Unix.cs" @@ -94,10 +91,62 @@ Link="Common\System\Security\Cryptography\ECOpenSsl.ImportExport.cs" /> <Compile Include="$(CommonPath)System\Security\Cryptography\KeyBlobHelpers.cs" Link="Common\System\Security\Cryptography\KeyBlobHelpers.cs" /> + <Compile Include="$(CommonPath)System\Security\Cryptography\KeyFormatHelper.cs" + Link="Common\System\Security\Cryptography\KeyFormatHelper.cs" /> + <Compile Include="$(CommonPath)System\Security\Cryptography\Oids.cs" + Link="Common\System\Security\Cryptography\Oids.cs" /> + <Compile Include="$(CommonPath)System\Security\Cryptography\RSAKeyFormatHelper.cs" + Link="Common\System\Security\Cryptography\RSAKeyFormatHelper.cs" /> <Compile Include="$(CommonPath)System\Security\Cryptography\RSAOpenSsl.cs" Link="Common\System\Security\Cryptography\RSAOpenSsl.cs" /> <Compile Include="$(CommonPath)System\Security\Cryptography\RsaPaddingProcessor.cs" Link="Common\System\Security\Cryptography\RsaPaddingProcessor.cs" /> + <AsnXml Include="$(CommonPath)System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml"> + <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml</Link> + </AsnXml> + <Compile Include="$(CommonPath)System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml.cs"> + <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml.cs</Link> + <DependentUpon>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml</DependentUpon> + </Compile> + <Compile Include="$(CommonPath)System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.manual.cs"> + <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.manual.cs</Link> + <DependentUpon>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml</DependentUpon> + </Compile> + <AsnXml Include="$(CommonPath)System\Security\Cryptography\Asn1\AttributeAsn.xml"> + <Link>Common\System\Security\Cryptography\Asn1\AttributeAsn.xml</Link> + </AsnXml> + <Compile Include="$(CommonPath)System\Security\Cryptography\Asn1\AttributeAsn.xml.cs"> + <Link>Common\System\Security\Cryptography\Asn1\AttributeAsn.xml.cs</Link> + <DependentUpon>Common\System\Security\Cryptography\Asn1\AttributeAsn.xml</DependentUpon> + </Compile> + <AsnXml Include="$(CommonPath)System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml"> + <Link>Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml</Link> + </AsnXml> + <Compile Include="$(CommonPath)System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml.cs"> + <Link>Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml.cs</Link> + <DependentUpon>Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml</DependentUpon> + </Compile> + <AsnXml Include="$(CommonPath)System\Security\Cryptography\Asn1\RSAPrivateKeyAsn.xml"> + <Link>Common\System\Security\Cryptography\Asn1\RSAPrivateKeyAsn.xml</Link> + </AsnXml> + <Compile Include="$(CommonPath)System\Security\Cryptography\Asn1\RSAPrivateKeyAsn.xml.cs"> + <Link>Common\System\Security\Cryptography\Asn1\RSAPrivateKeyAsn.xml.cs</Link> + <DependentUpon>Common\System\Security\Cryptography\Asn1\RSAPrivateKeyAsn.xml</DependentUpon> + </Compile> + <AsnXml Include="$(CommonPath)System\Security\Cryptography\Asn1\RSAPublicKeyAsn.xml"> + <Link>Common\System\Security\Cryptography\Asn1\RSAPublicKeyAsn.xml</Link> + </AsnXml> + <Compile Include="$(CommonPath)System\Security\Cryptography\Asn1\RSAPublicKeyAsn.xml.cs"> + <Link>Common\System\Security\Cryptography\Asn1\RSAPublicKeyAsn.xml.cs</Link> + <DependentUpon>Common\System\Security\Cryptography\Asn1\RSAPublicKeyAsn.xml</DependentUpon> + </Compile> + <AsnXml Include="$(CommonPath)System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml"> + <Link>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml</Link> + </AsnXml> + <Compile Include="$(CommonPath)System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml.cs"> + <Link>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml.cs</Link> + <DependentUpon>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml</DependentUpon> + </Compile> </ItemGroup> <ItemGroup> <ProjectReference Include="$(LibrariesProjectRoot)System.Formats.Asn1\src\System.Formats.Asn1.csproj" /> diff --git a/src/libraries/System.Security.Cryptography.OpenSsl/src/System/Security/Cryptography/RSAOpenSsl.cs b/src/libraries/System.Security.Cryptography.OpenSsl/src/System/Security/Cryptography/RSAOpenSsl.cs index eb7d7545928..c6f8efb7563 100644 --- a/src/libraries/System.Security.Cryptography.OpenSsl/src/System/Security/Cryptography/RSAOpenSsl.cs +++ b/src/libraries/System.Security.Cryptography.OpenSsl/src/System/Security/Cryptography/RSAOpenSsl.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics; using Microsoft.Win32.SafeHandles; namespace System.Security.Cryptography @@ -29,18 +30,10 @@ namespace System.Security.Cryptography if (handle == IntPtr.Zero) throw new ArgumentException(SR.Cryptography_OpenInvalidHandle, nameof(handle)); - SafeEvpPKeyHandle pkey = Interop.Crypto.EvpPkeyCreate(); + SafeEvpPKeyHandle pkey = Interop.Crypto.EvpPKeyCreateRsa(handle); + Debug.Assert(!pkey.IsInvalid); - if (!Interop.Crypto.EvpPkeySetRsa(pkey, handle)) - { - pkey.Dispose(); - throw Interop.Crypto.CreateOpenSslCryptographicException(); - } - - // Use ForceSet instead of the property setter to ensure that LegalKeySizes doesn't interfere - // with the already loaded key. - ForceSetKeySize(BitsPerByte * Interop.Crypto.EvpPKeySize(pkey)); - _key = new Lazy<SafeEvpPKeyHandle>(pkey); + SetKey(pkey); } /// <summary> @@ -60,21 +53,11 @@ namespace System.Security.Cryptography if (pkeyHandle.IsInvalid) throw new ArgumentException(SR.Cryptography_OpenInvalidHandle, nameof(pkeyHandle)); - SafeEvpPKeyHandle newKey = Interop.Crypto.EvpPkeyCreate(); - - using (SafeRsaHandle rsa = Interop.Crypto.EvpPkeyGetRsa(pkeyHandle)) - { - if (rsa.IsInvalid || !Interop.Crypto.EvpPkeySetRsa(newKey, rsa)) - { - newKey.Dispose(); - throw Interop.Crypto.CreateOpenSslCryptographicException(); - } - } + SafeEvpPKeyHandle newKey = Interop.Crypto.EvpPKeyDuplicate( + pkeyHandle, + Interop.Crypto.EvpAlgorithmId.RSA); - // Use ForceSet instead of the property setter to ensure that LegalKeySizes doesn't interfere - // with the already loaded key. - ForceSetKeySize(BitsPerByte * Interop.Crypto.EvpPKeySize(newKey)); - _key = new Lazy<SafeEvpPKeyHandle>(newKey); + SetKey(newKey); } /// <summary> @@ -84,18 +67,7 @@ namespace System.Security.Cryptography /// <returns>A SafeHandle for the RSA key in OpenSSL</returns> public SafeEvpPKeyHandle DuplicateKeyHandle() { - SafeEvpPKeyHandle pkeyHandle = Interop.Crypto.EvpPkeyCreate(); - - using (SafeRsaHandle rsa = Interop.Crypto.EvpPkeyGetRsa(GetKey())) - { - if (rsa.IsInvalid || !Interop.Crypto.EvpPkeySetRsa(pkeyHandle, rsa)) - { - pkeyHandle.Dispose(); - throw Interop.Crypto.CreateOpenSslCryptographicException(); - } - } - - return pkeyHandle; + return Interop.Crypto.EvpPKeyDuplicate(GetKey(), Interop.Crypto.EvpAlgorithmId.RSA); } } } diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/System.Security.Cryptography.Pkcs.csproj b/src/libraries/System.Security.Cryptography.Pkcs/src/System.Security.Cryptography.Pkcs.csproj index 88bce55ee44..059c3fffb7b 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/src/System.Security.Cryptography.Pkcs.csproj +++ b/src/libraries/System.Security.Cryptography.Pkcs/src/System.Security.Cryptography.Pkcs.csproj @@ -551,6 +551,8 @@ <ItemGroup Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'netstandard2.1'))"> <Compile Include="$(CommonPath)System\Security\Cryptography\KeyFormatHelper.cs" Link="Common\System\Security\Cryptography\KeyFormatHelper.cs" /> + <Compile Include="$(CommonPath)System\Security\Cryptography\KeyFormatHelper.Encrypted.cs" + Link="Common\System\Security\Cryptography\KeyFormatHelper.Encrypted.cs" /> <AsnXml Include="$(CommonPath)System\Security\Cryptography\Asn1\DigestInfoAsn.xml"> <Link>Common\System\Security\Cryptography\Asn1\DigestInfoAsn.xml</Link> </AsnXml> diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/System.Security.Cryptography.X509Certificates.csproj b/src/libraries/System.Security.Cryptography.X509Certificates/src/System.Security.Cryptography.X509Certificates.csproj index 505d487f1d4..3b1071dd912 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/System.Security.Cryptography.X509Certificates.csproj +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/System.Security.Cryptography.X509Certificates.csproj @@ -14,7 +14,7 @@ <UseAppleCrypto Condition="'$(TargetsOSX)' == 'true' or '$(TargetsiOS)' == 'true' or '$(TargetstvOS)' == 'true'">true</UseAppleCrypto> </PropertyGroup> <Import Project="$(CommonPath)System\Security\Cryptography\Asn1\AsnXml.targets" /> - <Import Project="$(CommonPath)System\Security\Cryptography\Asn1Reader\System.Security.Cryptography.Asn1Reader.Shared.projitems" /> + <Import Project="$(CommonPath)System\Security\Cryptography\Asn1Reader\System.Security.Cryptography.Asn1Reader.Shared.projitems" Condition="'$(TargetsAnyOS)' != 'true'" /> <ItemGroup Condition="'$(TargetsAnyOS)' != 'true'"> <Compile Include="Internal\Cryptography\ICertificatePal.cs" /> <Compile Include="Internal\Cryptography\ICertificatePalCore.cs" /> @@ -518,6 +518,8 @@ Link="Common\System\Security\Cryptography\ECDiffieHellmanDerivation.cs" /> <Compile Include="$(CommonPath)System\Security\Cryptography\RSAKeyFormatHelper.cs" Link="Common\System\Security\Cryptography\RSAKeyFormatHelper.cs" /> + <Compile Include="$(CommonPath)System\Security\Cryptography\RSAKeyFormatHelper.Encrypted.cs" + Link="Common\System\Security\Cryptography\RSAKeyFormatHelper.Encrypted.cs" /> <Compile Include="$(CommonPath)System\Security\Cryptography\RsaPaddingProcessor.cs" Link="Common\System\Security\Cryptography\RsaPaddingProcessor.cs" /> <Compile Include="$(CommonPath)System\Security\Cryptography\RSASecurityTransforms.cs" @@ -642,6 +644,8 @@ <ItemGroup Condition=" '$(TargetsUnix)' == 'true'"> <Compile Include="$(CommonPath)System\Security\Cryptography\KeyFormatHelper.cs" Link="Common\System\Security\Cryptography\KeyFormatHelper.cs" /> + <Compile Include="$(CommonPath)System\Security\Cryptography\KeyFormatHelper.Encrypted.cs" + Link="Common\System\Security\Cryptography\KeyFormatHelper.Encrypted.cs" /> <Compile Include="$(CommonPath)System\Security\Cryptography\PasswordBasedEncryption.cs" Link="Common\System\Security\Cryptography\PasswordBasedEncryption.cs" /> <Compile Include="$(CommonPath)System\Security\Cryptography\Pkcs12Kdf.cs" |