Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJeremy Barton <jbarton@microsoft.com>2021-07-14 04:20:19 +0300
committerGitHub <noreply@github.com>2021-07-14 04:20:19 +0300
commitf94711de4518163b073734cae2a4d47f5398573c (patch)
treea7fb8ac9972edb18c2580069a5a9f684941d8e19 /src
parentf6eb259db626d563c15ba340feb6f440d1e1c8ee (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')
-rw-r--r--src/libraries/Common/src/Internal/Cryptography/Helpers.cs2
-rw-r--r--src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs29
-rw-r--r--src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.cs193
-rw-r--r--src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs136
-rw-r--r--src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeRsaHandle.Unix.cs47
-rw-r--r--src/libraries/Common/src/System/Security/Cryptography/Asn1/AlgorithmIdentifierAsn.manual.cs2
-rw-r--r--src/libraries/Common/src/System/Security/Cryptography/Asn1Reader/AsnValueReader.cs7
-rw-r--r--src/libraries/Common/src/System/Security/Cryptography/KeyFormatHelper.Encrypted.cs393
-rw-r--r--src/libraries/Common/src/System/Security/Cryptography/KeyFormatHelper.cs381
-rw-r--r--src/libraries/Common/src/System/Security/Cryptography/RSAKeyFormatHelper.Encrypted.cs38
-rw-r--r--src/libraries/Common/src/System/Security/Cryptography/RSAKeyFormatHelper.cs63
-rw-r--r--src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs374
-rw-r--r--src/libraries/Native/Unix/System.Security.Cryptography.Native/CMakeLists.txt1
-rw-r--r--src/libraries/Native/Unix/System.Security.Cryptography.Native/apibridge.c59
-rw-r--r--src/libraries/Native/Unix/System.Security.Cryptography.Native/apibridge.h2
-rw-r--r--src/libraries/Native/Unix/System.Security.Cryptography.Native/entrypoints.c18
-rw-r--r--src/libraries/Native/Unix/System.Security.Cryptography.Native/opensslshim.h20
-rw-r--r--src/libraries/Native/Unix/System.Security.Cryptography.Native/osslcompat_111.h2
-rw-r--r--src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.c167
-rw-r--r--src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.h48
-rw-r--r--src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c30
-rw-r--r--src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h19
-rw-r--r--src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_rsa.c249
-rw-r--r--src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_rsa.h79
-rw-r--r--src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_ssl.c3
-rw-r--r--src/libraries/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj12
-rw-r--r--src/libraries/System.Security.Cryptography.Cng/src/System.Security.Cryptography.Cng.csproj2
-rw-r--r--src/libraries/System.Security.Cryptography.OpenSsl/src/Resources/Strings.resx9
-rw-r--r--src/libraries/System.Security.Cryptography.OpenSsl/src/System.Security.Cryptography.OpenSsl.csproj57
-rw-r--r--src/libraries/System.Security.Cryptography.OpenSsl/src/System/Security/Cryptography/RSAOpenSsl.cs46
-rw-r--r--src/libraries/System.Security.Cryptography.Pkcs/src/System.Security.Cryptography.Pkcs.csproj2
-rw-r--r--src/libraries/System.Security.Cryptography.X509Certificates/src/System.Security.Cryptography.X509Certificates.csproj6
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"