From 04d26184825dcd9218daf40eedfda596d4ee4259 Mon Sep 17 00:00:00 2001 From: Filip Navara Date: Wed, 28 Apr 2021 10:50:44 +0200 Subject: [PATCH] Use data keys on macOS for RSA, EC cryptography --- .../Interop.RSA.cs | 24 -- .../Interop.SecKeyRef.cs | 89 ++++++ .../Interop.SecKeyRef.iOS.cs | 95 ------ .../Cryptography/EccSecurityTransforms.cs | 124 ++++++++ .../Cryptography/EccSecurityTransforms.iOS.cs | 117 +------ .../EccSecurityTransforms.macOS.cs | 118 +------ .../Cryptography/RSASecurityTransforms.cs | 295 ++++++++++++------ .../Cryptography/RSASecurityTransforms.iOS.cs | 149 +-------- .../RSASecurityTransforms.macOS.cs | 127 ++------ .../entrypoints.c | 1 - .../pal_rsa.c | 7 - ...em.Security.Cryptography.Algorithms.csproj | 8 +- .../Pal.OSX/AppleCertificatePal.cs | 50 ++- .../Cryptography/Pal.OSX/ApplePkcs12Reader.cs | 21 +- ...urity.Cryptography.X509Certificates.csproj | 8 +- 15 files changed, 500 insertions(+), 733 deletions(-) delete mode 100644 src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.SecKeyRef.iOS.cs diff --git a/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.RSA.cs b/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.RSA.cs index 2b8278406605c..f0ebcf94d95e5 100644 --- a/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.RSA.cs +++ b/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.RSA.cs @@ -35,14 +35,6 @@ private static extern int AppleCryptoNative_RsaVerificationPrimitive( out SafeCFDataHandle pDataOut, out SafeCFErrorHandle pErrorOut); - [DllImport(Libraries.AppleCryptoNative)] - private static extern int AppleCryptoNative_RsaDecryptionPrimitive( - SafeSecKeyRefHandle privateKey, - ref byte pbData, - int cbData, - out SafeCFDataHandle pDataOut, - out SafeCFErrorHandle pErrorOut); - [DllImport(Libraries.AppleCryptoNative)] private static extern int AppleCryptoNative_RsaEncryptionPrimitive( SafeSecKeyRefHandle publicKey, @@ -270,22 +262,6 @@ private static bool ProcessPrimitiveResponse( throw new CryptographicException(); } - internal static bool TryRsaDecryptionPrimitive( - SafeSecKeyRefHandle privateKey, - ReadOnlySpan source, - Span destination, - out int bytesWritten) - { - int returnValue = AppleCryptoNative_RsaDecryptionPrimitive( - privateKey, - ref MemoryMarshal.GetReference(source), - source.Length, - out SafeCFDataHandle cfData, - out SafeCFErrorHandle cfError); - - return ProcessPrimitiveResponse(returnValue, cfData, cfError, destination, out bytesWritten); - } - internal static bool TryRsaEncryptionPrimitive( SafeSecKeyRefHandle publicKey, ReadOnlySpan source, diff --git a/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.SecKeyRef.cs b/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.SecKeyRef.cs index 1e83ae065f202..a479faf2be559 100644 --- a/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.SecKeyRef.cs +++ b/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.SecKeyRef.cs @@ -16,6 +16,13 @@ internal static partial class AppleCrypto private const int kErrorSeeError = -2; private const int kPlatformNotSupported = -5; + internal enum PAL_KeyAlgorithm : uint + { + Unknown = 0, + EC = 1, + RSA = 2, + } + [DllImport(Libraries.AppleCryptoNative)] private static extern ulong AppleCryptoNative_SecKeyGetSimpleKeySizeInBytes(SafeSecKeyRefHandle publicKey); @@ -82,6 +89,88 @@ internal static int GetSimpleKeySizeInBits(SafeSecKeyRefHandle publicKey) return (int)(keySizeInBytes * 8); } } + + internal static unsafe SafeSecKeyRefHandle CreateDataKey( + ReadOnlySpan keyData, + PAL_KeyAlgorithm keyAlgorithm, + bool isPublic) + { + fixed (byte* pKey = keyData) + { + int result = AppleCryptoNative_SecKeyCreateWithData( + pKey, + keyData.Length, + keyAlgorithm, + isPublic ? 1 : 0, + out SafeSecKeyRefHandle dataKey, + out SafeCFErrorHandle errorHandle); + + using (errorHandle) + { + switch (result) + { + case kSuccess: + return dataKey; + case kErrorSeeError: + throw CreateExceptionForCFError(errorHandle); + default: + Debug.Fail($"SecKeyCreateWithData returned {result}"); + throw new CryptographicException(); + } + } + } + } + + internal static bool TrySecKeyCopyExternalRepresentation( + SafeSecKeyRefHandle key, + out byte[] externalRepresentation) + { + const int errSecPassphraseRequired = -25260; + + int result = AppleCryptoNative_SecKeyCopyExternalRepresentation( + key, + out SafeCFDataHandle data, + out SafeCFErrorHandle errorHandle); + + using (errorHandle) + using (data) + { + switch (result) + { + case kSuccess: + externalRepresentation = CoreFoundation.CFGetData(data); + return true; + case kErrorSeeError: + if (Interop.CoreFoundation.GetErrorCode(errorHandle) == errSecPassphraseRequired) + { + externalRepresentation = Array.Empty(); + return false; + } + throw CreateExceptionForCFError(errorHandle); + default: + Debug.Fail($"SecKeyCopyExternalRepresentation returned {result}"); + throw new CryptographicException(); + } + } + } + + [DllImport(Libraries.AppleCryptoNative)] + private static unsafe extern int AppleCryptoNative_SecKeyCreateWithData( + byte* pKey, + int cbKey, + PAL_KeyAlgorithm keyAlgorithm, + int isPublic, + out SafeSecKeyRefHandle pDataKey, + out SafeCFErrorHandle pErrorOut); + + [DllImport(Libraries.AppleCryptoNative)] + private static unsafe extern int AppleCryptoNative_SecKeyCopyExternalRepresentation( + SafeSecKeyRefHandle key, + out SafeCFDataHandle pDataOut, + out SafeCFErrorHandle pErrorOut); + + [DllImport(Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_SecKeyCopyPublicKey")] + internal static unsafe extern SafeSecKeyRefHandle CopyPublicKey(SafeSecKeyRefHandle privateKey); } } diff --git a/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.SecKeyRef.iOS.cs b/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.SecKeyRef.iOS.cs deleted file mode 100644 index edaf30646179f..0000000000000 --- a/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.SecKeyRef.iOS.cs +++ /dev/null @@ -1,95 +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 System.Security.Cryptography.Apple; -using Microsoft.Win32.SafeHandles; - -internal static partial class Interop -{ - internal static partial class AppleCrypto - { - internal enum PAL_KeyAlgorithm : uint - { - Unknown = 0, - EC = 1, - RSA = 2, - } - - internal static unsafe SafeSecKeyRefHandle CreateDataKey( - ReadOnlySpan keyData, - PAL_KeyAlgorithm keyAlgorithm, - bool isPublic) - { - fixed (byte* pKey = keyData) - { - int result = AppleCryptoNative_SecKeyCreateWithData( - pKey, - keyData.Length, - keyAlgorithm, - isPublic ? 1 : 0, - out SafeSecKeyRefHandle dataKey, - out SafeCFErrorHandle errorHandle); - - using (errorHandle) - { - switch (result) - { - case kSuccess: - return dataKey; - case kErrorSeeError: - throw CreateExceptionForCFError(errorHandle); - default: - Debug.Fail($"SecKeyCreateWithData returned {result}"); - throw new CryptographicException(); - } - } - } - } - - internal static byte[] SecKeyCopyExternalRepresentation( - SafeSecKeyRefHandle key) - { - int result = AppleCryptoNative_SecKeyCopyExternalRepresentation( - key, - out SafeCFDataHandle data, - out SafeCFErrorHandle errorHandle); - - using (errorHandle) - using (data) - { - switch (result) - { - case kSuccess: - return CoreFoundation.CFGetData(data); - case kErrorSeeError: - throw CreateExceptionForCFError(errorHandle); - default: - Debug.Fail($"SecKeyCopyExternalRepresentation returned {result}"); - throw new CryptographicException(); - } - } - } - - [DllImport(Libraries.AppleCryptoNative)] - private static unsafe extern int AppleCryptoNative_SecKeyCreateWithData( - byte* pKey, - int cbKey, - PAL_KeyAlgorithm keyAlgorithm, - int isPublic, - out SafeSecKeyRefHandle pDataKey, - out SafeCFErrorHandle pErrorOut); - - [DllImport(Libraries.AppleCryptoNative)] - private static unsafe extern int AppleCryptoNative_SecKeyCopyExternalRepresentation( - SafeSecKeyRefHandle key, - out SafeCFDataHandle pDataOut, - out SafeCFErrorHandle pErrorOut); - - [DllImport(Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_SecKeyCopyPublicKey")] - internal static unsafe extern SafeSecKeyRefHandle CopyPublicKey(SafeSecKeyRefHandle privateKey); - } -} diff --git a/src/libraries/Common/src/System/Security/Cryptography/EccSecurityTransforms.cs b/src/libraries/Common/src/System/Security/Cryptography/EccSecurityTransforms.cs index c6f94fe9e8ac5..6d16c38f68baa 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/EccSecurityTransforms.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/EccSecurityTransforms.cs @@ -116,11 +116,135 @@ private void SetKey(SecKeyPair keyPair) current?.Dispose(); } + internal ECParameters ExportParameters(bool includePrivateParameters, int keySizeInBits) + { + SecKeyPair keys = GetOrGenerateKeys(keySizeInBits); + + if (includePrivateParameters && keys.PrivateKey == null) + { + throw new CryptographicException(SR.Cryptography_OpenInvalidHandle); + } + + bool gotKeyBlob = Interop.AppleCrypto.TrySecKeyCopyExternalRepresentation( + includePrivateParameters ? keys.PrivateKey! : keys.PublicKey, + out byte[] keyBlob); + + if (!gotKeyBlob) + { + return ExportParametersFromLegacyKey(keys, includePrivateParameters); + } + + try + { + AsymmetricAlgorithmHelpers.DecodeFromUncompressedAnsiX963Key( + keyBlob, + includePrivateParameters, + out ECParameters key); + + switch (GetKeySize(keys)) + { + case 256: key.Curve = ECCurve.NamedCurves.nistP256; break; + case 384: key.Curve = ECCurve.NamedCurves.nistP384; break; + case 521: key.Curve = ECCurve.NamedCurves.nistP521; break; + default: + Debug.Fail("Unsupported curve"); + throw new CryptographicException(); + } + + return key; + } + finally + { + CryptographicOperations.ZeroMemory(keyBlob); + } + } + + internal int ImportParameters(ECParameters parameters) + { + parameters.Validate(); + ThrowIfDisposed(); + + if (!parameters.Curve.IsNamed) + { + throw new PlatformNotSupportedException(SR.Cryptography_ECC_NamedCurvesOnly); + } + + switch (parameters.Curve.Oid.Value) + { + case Oids.secp256r1: + case Oids.secp384r1: + case Oids.secp521r1: + break; + default: + throw new PlatformNotSupportedException( + SR.Format(SR.Cryptography_CurveNotSupported, parameters.Curve.Oid.Value ?? parameters.Curve.Oid.FriendlyName)); + } + + if (parameters.Q.X == null || parameters.Q.Y == null) + { + ExtractPublicKeyFromPrivateKey(ref parameters); + } + + bool isPrivateKey = parameters.D != null; + SecKeyPair newKeys; + + if (isPrivateKey) + { + // Start with the private key, in case some of the private key fields don't + // match the public key fields and the system determines an integrity failure. + // + // Public import should go off without a hitch. + SafeSecKeyRefHandle privateKey = ImportKey(parameters); + SafeSecKeyRefHandle publicKey = Interop.AppleCrypto.CopyPublicKey(privateKey); + newKeys = SecKeyPair.PublicPrivatePair(publicKey, privateKey); + } + else + { + SafeSecKeyRefHandle publicKey = ImportKey(parameters); + newKeys = SecKeyPair.PublicOnly(publicKey); + } + + int size = GetKeySize(newKeys); + SetKey(newKeys); + + return size; + } + private static int GetKeySize(SecKeyPair newKeys) { long size = Interop.AppleCrypto.EccGetKeySizeInBits(newKeys.PublicKey); Debug.Assert(size == 256 || size == 384 || size == 521, $"Unknown keysize ({size})"); return (int)size; } + + private static SafeSecKeyRefHandle ImportKey(ECParameters parameters) + { + int fieldSize = parameters.Q!.X!.Length; + + Debug.Assert(parameters.Q.Y != null && parameters.Q.Y.Length == fieldSize); + Debug.Assert(parameters.Q.X != null && parameters.Q.X.Length == fieldSize); + + int keySize = 1 + fieldSize * (parameters.D != null ? 3 : 2); + byte[] dataKeyPool = CryptoPool.Rent(keySize); + Span dataKey = dataKeyPool.AsSpan(0, keySize); + + try + { + AsymmetricAlgorithmHelpers.EncodeToUncompressedAnsiX963Key( + parameters.Q.X, + parameters.Q.Y, + parameters.D, + dataKey); + + return Interop.AppleCrypto.CreateDataKey( + dataKey, + Interop.AppleCrypto.PAL_KeyAlgorithm.EC, + isPublic: parameters.D == null); + } + finally + { + CryptoPool.Return(dataKeyPool, keySize); + } + } } } diff --git a/src/libraries/Common/src/System/Security/Cryptography/EccSecurityTransforms.iOS.cs b/src/libraries/Common/src/System/Security/Cryptography/EccSecurityTransforms.iOS.cs index 44f17a8b88304..da5ac482a2700 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/EccSecurityTransforms.iOS.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/EccSecurityTransforms.iOS.cs @@ -12,119 +12,10 @@ namespace System.Security.Cryptography { internal sealed partial class EccSecurityTransforms { - internal ECParameters ExportParameters(bool includePrivateParameters, int keySizeInBits) - { - SecKeyPair keys = GetOrGenerateKeys(keySizeInBits); + private static ECParameters ExportParametersFromLegacyKey(SecKeyPair keys, bool includePrivateParameters) + => throw new CryptographicException(); - if (includePrivateParameters && keys.PrivateKey == null) - { - throw new CryptographicException(SR.Cryptography_OpenInvalidHandle); - } - - byte[] keyBlob = Interop.AppleCrypto.SecKeyCopyExternalRepresentation( - includePrivateParameters ? keys.PrivateKey! : keys.PublicKey); - - try - { - AsymmetricAlgorithmHelpers.DecodeFromUncompressedAnsiX963Key( - keyBlob, - includePrivateParameters, - out ECParameters key); - - switch (GetKeySize(keys)) - { - case 256: key.Curve = ECCurve.NamedCurves.nistP256; break; - case 384: key.Curve = ECCurve.NamedCurves.nistP384; break; - case 521: key.Curve = ECCurve.NamedCurves.nistP521; break; - } - - return key; - } - finally - { - CryptographicOperations.ZeroMemory(keyBlob); - } - } - - internal int ImportParameters(ECParameters parameters) - { - parameters.Validate(); - ThrowIfDisposed(); - - if (!parameters.Curve.IsNamed) - { - throw new PlatformNotSupportedException(SR.Cryptography_ECC_NamedCurvesOnly); - } - - switch (parameters.Curve.Oid.Value) - { - case Oids.secp256r1: - case Oids.secp384r1: - case Oids.secp521r1: - break; - default: - throw new PlatformNotSupportedException( - SR.Format(SR.Cryptography_CurveNotSupported, parameters.Curve.Oid.Value ?? parameters.Curve.Oid.FriendlyName)); - } - - if (parameters.Q.X == null || parameters.Q.Y == null) - { - throw new PlatformNotSupportedException(SR.Cryptography_NotValidPublicOrPrivateKey); - } - - bool isPrivateKey = parameters.D != null; - SecKeyPair newKeys; - - if (isPrivateKey) - { - // Start with the private key, in case some of the private key fields don't - // match the public key fields and the system determines an integrity failure. - // - // Public import should go off without a hitch. - SafeSecKeyRefHandle privateKey = ImportKey(parameters); - SafeSecKeyRefHandle publicKey = Interop.AppleCrypto.CopyPublicKey(privateKey); - newKeys = SecKeyPair.PublicPrivatePair(publicKey, privateKey); - } - else - { - SafeSecKeyRefHandle publicKey = ImportKey(parameters); - newKeys = SecKeyPair.PublicOnly(publicKey); - } - - int size = GetKeySize(newKeys); - SetKey(newKeys); - - return size; - } - - private static SafeSecKeyRefHandle ImportKey(ECParameters parameters) - { - int fieldSize = parameters.Q!.X!.Length; - - Debug.Assert(parameters.Q.Y != null && parameters.Q.Y.Length == fieldSize); - Debug.Assert(parameters.Q.X != null && parameters.Q.X.Length == fieldSize); - - int keySize = 1 + fieldSize * (parameters.D != null ? 3 : 2); - byte[] dataKeyPool = CryptoPool.Rent(keySize); - Span dataKey = dataKeyPool.AsSpan(0, keySize); - - try - { - AsymmetricAlgorithmHelpers.EncodeToUncompressedAnsiX963Key( - parameters.Q.X, - parameters.Q.Y, - parameters.D, - dataKey); - - return Interop.AppleCrypto.CreateDataKey( - dataKey, - Interop.AppleCrypto.PAL_KeyAlgorithm.EC, - isPublic: parameters.D == null); - } - finally - { - CryptoPool.Return(dataKeyPool, keySize); - } - } + private static void ExtractPublicKeyFromPrivateKey(ref ECParameters ecParameters) + => throw new PlatformNotSupportedException(SR.Cryptography_NotValidPublicOrPrivateKey); } } diff --git a/src/libraries/Common/src/System/Security/Cryptography/EccSecurityTransforms.macOS.cs b/src/libraries/Common/src/System/Security/Cryptography/EccSecurityTransforms.macOS.cs index a47dcd6593b04..af0bdd21d7dc9 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/EccSecurityTransforms.macOS.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/EccSecurityTransforms.macOS.cs @@ -12,28 +12,11 @@ namespace System.Security.Cryptography { internal sealed partial class EccSecurityTransforms { - internal static ECParameters ExportPublicParametersFromPrivateKey(SafeSecKeyRefHandle handle) - { - const string ExportPassword = "DotnetExportPassphrase"; - byte[] keyBlob = Interop.AppleCrypto.SecKeyExport(handle, exportPrivate: true, password: ExportPassword); - EccKeyFormatHelper.ReadEncryptedPkcs8(keyBlob, ExportPassword, out _, out ECParameters key); - CryptographicOperations.ZeroMemory(key.D); - CryptographicOperations.ZeroMemory(keyBlob); - key.D = null; - return key; - } - - internal ECParameters ExportParameters(bool includePrivateParameters, int keySizeInBits) + private static ECParameters ExportParametersFromLegacyKey(SecKeyPair keys, bool includePrivateParameters) { // Apple requires all private keys to be exported encrypted, but since we're trying to export // as parsed structures we will need to decrypt it for the user. const string ExportPassword = "DotnetExportPassphrase"; - SecKeyPair keys = GetOrGenerateKeys(keySizeInBits); - - if (includePrivateParameters && keys.PrivateKey == null) - { - throw new CryptographicException(SR.Cryptography_OpenInvalidHandle); - } byte[] keyBlob = Interop.AppleCrypto.SecKeyExport( includePrivateParameters ? keys.PrivateKey : keys.PublicKey, @@ -66,75 +49,20 @@ internal ECParameters ExportParameters(bool includePrivateParameters, int keySiz } } - internal int ImportParameters(ECParameters parameters) + private static void ExtractPublicKeyFromPrivateKey(ref ECParameters ecParameters) { - parameters.Validate(); - ThrowIfDisposed(); - - bool isPrivateKey = parameters.D != null; - bool hasPublicParameters = parameters.Q.X != null && parameters.Q.Y != null; - SecKeyPair newKeys; - - if (isPrivateKey) + using (SafeSecKeyRefHandle secPrivateKey = ImportLegacyPrivateKey(ref ecParameters)) { - // Start with the private key, in case some of the private key fields don't - // match the public key fields and the system determines an integrity failure. - // - // Public import should go off without a hitch. - SafeSecKeyRefHandle privateKey = ImportKey(parameters); - - ECParameters publicOnly; - - if (hasPublicParameters) - { - publicOnly = parameters; - publicOnly.D = null; - } - else - { - publicOnly = ExportPublicParametersFromPrivateKey(privateKey); - } - - SafeSecKeyRefHandle publicKey; - try - { - publicKey = ImportKey(publicOnly); - } - catch - { - privateKey.Dispose(); - throw; - } - - newKeys = SecKeyPair.PublicPrivatePair(publicKey, privateKey); - } - else - { - SafeSecKeyRefHandle publicKey = ImportKey(parameters); - newKeys = SecKeyPair.PublicOnly(publicKey); + const string ExportPassword = "DotnetExportPassphrase"; + byte[] keyBlob = Interop.AppleCrypto.SecKeyExport(secPrivateKey, exportPrivate: true, password: ExportPassword); + EccKeyFormatHelper.ReadEncryptedPkcs8(keyBlob, ExportPassword, out _, out ecParameters); + CryptographicOperations.ZeroMemory(keyBlob); } - - int size = GetKeySize(newKeys); - SetKey(newKeys); - - return size; } - private static SafeSecKeyRefHandle ImportKey(ECParameters parameters) + private static SafeSecKeyRefHandle ImportLegacyPrivateKey(ref ECParameters parameters) { - AsnWriter keyWriter; - bool hasPrivateKey; - - if (parameters.D != null) - { - keyWriter = EccKeyFormatHelper.WriteECPrivateKey(parameters); - hasPrivateKey = true; - } - else - { - keyWriter = EccKeyFormatHelper.WriteSubjectPublicKeyInfo(parameters); - hasPrivateKey = false; - } + AsnWriter keyWriter = EccKeyFormatHelper.WriteECPrivateKey(parameters); byte[] rented = CryptoPool.Rent(keyWriter.GetEncodedLength()); @@ -149,38 +77,12 @@ private static SafeSecKeyRefHandle ImportKey(ECParameters parameters) try { - return Interop.AppleCrypto.ImportEphemeralKey(rented.AsSpan(0, written), hasPrivateKey); + return Interop.AppleCrypto.ImportEphemeralKey(rented.AsSpan(0, written), true); } finally { CryptoPool.Return(rented, written); } } - - internal unsafe int ImportSubjectPublicKeyInfo( - ReadOnlySpan source, - out int bytesRead) - { - ThrowIfDisposed(); - - fixed (byte* ptr = &MemoryMarshal.GetReference(source)) - { - using (MemoryManager manager = new PointerMemoryManager(ptr, source.Length)) - { - // Validate the DER value and get the number of bytes. - EccKeyFormatHelper.ReadSubjectPublicKeyInfo( - manager.Memory, - out int localRead); - - SafeSecKeyRefHandle publicKey = Interop.AppleCrypto.ImportEphemeralKey(source.Slice(0, localRead), false); - SecKeyPair newKeys = SecKeyPair.PublicOnly(publicKey); - int size = GetKeySize(newKeys); - SetKey(newKeys); - - bytesRead = localRead; - return size; - } - } - } } } diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSASecurityTransforms.cs b/src/libraries/Common/src/System/Security/Cryptography/RSASecurityTransforms.cs index 1123b6ce38d4f..9c02118e27ed0 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSASecurityTransforms.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSASecurityTransforms.cs @@ -87,6 +87,119 @@ public override int KeySize } } + public override RSAParameters ExportParameters(bool includePrivateParameters) + { + SecKeyPair keys = GetKeys(); + + if (includePrivateParameters && keys.PrivateKey == null) + { + throw new CryptographicException(SR.Cryptography_OpenInvalidHandle); + } + + bool gotKeyBlob = Interop.AppleCrypto.TrySecKeyCopyExternalRepresentation( + includePrivateParameters ? keys.PrivateKey! : keys.PublicKey, + out byte[] keyBlob); + + if (!gotKeyBlob) + { + return ExportParametersFromLegacyKey(keys, includePrivateParameters); + } + + try + { + if (!includePrivateParameters) + { + // When exporting a key handle opened from a certificate, it seems to + // export as a PKCS#1 blob instead of an X509 SubjectPublicKeyInfo blob. + // So, check for that. + // NOTE: It doesn't affect macOS Mojave when SecCertificateCopyKey API + // is used. + RSAParameters key; + + AsnReader reader = new AsnReader(keyBlob, AsnEncodingRules.BER); + AsnReader sequenceReader = reader.ReadSequence(); + + if (sequenceReader.PeekTag().Equals(Asn1Tag.Integer)) + { + AlgorithmIdentifierAsn ignored = default; + RSAKeyFormatHelper.ReadRsaPublicKey(keyBlob, ignored, out key); + } + else + { + RSAKeyFormatHelper.ReadSubjectPublicKeyInfo( + keyBlob, + out int localRead, + out key); + Debug.Assert(localRead == keyBlob.Length); + } + return key; + } + else + { + AlgorithmIdentifierAsn ignored = default; + RSAKeyFormatHelper.FromPkcs1PrivateKey( + keyBlob, + ignored, + out RSAParameters key); + return key; + } + } + finally + { + CryptographicOperations.ZeroMemory(keyBlob); + } + } + + public override void ImportParameters(RSAParameters parameters) + { + ValidateParameters(parameters); + ThrowIfDisposed(); + + bool isPrivateKey = parameters.D != null; + + if (isPrivateKey) + { + // Start with the private key, in case some of the private key fields + // don't match the public key fields. + // + // Public import should go off without a hitch. + ImportPrivateKey( + parameters, + out SafeSecKeyRefHandle privateKey, + out SafeSecKeyRefHandle publicKey); + SetKey(SecKeyPair.PublicPrivatePair(publicKey, privateKey)); + } + else + { + SafeSecKeyRefHandle publicKey = ImportKey(parameters); + SetKey(SecKeyPair.PublicOnly(publicKey)); + } + } + + public override unsafe void ImportRSAPublicKey(ReadOnlySpan source, out int bytesRead) + { + ThrowIfDisposed(); + + fixed (byte* ptr = &MemoryMarshal.GetReference(source)) + { + using (MemoryManager manager = new PointerMemoryManager(ptr, source.Length)) + { + // Validate the DER value and get the number of bytes. + RSAKeyFormatHelper.ReadRsaPublicKey( + manager.Memory, + out int localRead); + + SafeSecKeyRefHandle publicKey = Interop.AppleCrypto.CreateDataKey( + source.Slice(0, localRead), + Interop.AppleCrypto.PAL_KeyAlgorithm.RSA, + isPublic: true); + SetKey(SecKeyPair.PublicOnly(publicKey)); + + bytesRead = localRead; + } + } + } + public override void ImportEncryptedPkcs8PrivateKey( ReadOnlySpan passwordBytes, ReadOnlySpan source, @@ -149,65 +262,56 @@ public override bool TryEncrypt(ReadOnlySpan data, Span destination, return false; } - if (padding == RSAEncryptionPadding.Pkcs1 && data.Length > 0) + if (data.Length == 0) { - const int Pkcs1PaddingOverhead = 11; - int maxAllowed = rsaSize - Pkcs1PaddingOverhead; + RsaPaddingProcessor? processor; - if (data.Length > maxAllowed) + switch (padding.Mode) { - throw new CryptographicException( - SR.Format(SR.Cryptography_Encryption_MessageTooLong, maxAllowed)); + case RSAEncryptionPaddingMode.Pkcs1: + processor = null; + break; + case RSAEncryptionPaddingMode.Oaep: + processor = RsaPaddingProcessor.OpenProcessor(padding.OaepHashAlgorithm); + break; + default: + throw new CryptographicException(SR.Cryptography_InvalidPaddingMode); } - return Interop.AppleCrypto.TryRsaEncrypt( - GetKeys().PublicKey, - data, - destination, - padding, - out bytesWritten); - } - - RsaPaddingProcessor? processor; - - switch (padding.Mode) - { - case RSAEncryptionPaddingMode.Pkcs1: - processor = null; - break; - case RSAEncryptionPaddingMode.Oaep: - processor = RsaPaddingProcessor.OpenProcessor(padding.OaepHashAlgorithm); - break; - default: - throw new CryptographicException(SR.Cryptography_InvalidPaddingMode); - } - - byte[] rented = CryptoPool.Rent(rsaSize); - Span tmp = new Span(rented, 0, rsaSize); + byte[] rented = CryptoPool.Rent(rsaSize); + Span tmp = new Span(rented, 0, rsaSize); - try - { - if (processor != null) + try { - processor.PadOaep(data, tmp); + if (processor != null) + { + processor.PadOaep(data, tmp); + } + else + { + Debug.Assert(padding.Mode == RSAEncryptionPaddingMode.Pkcs1); + RsaPaddingProcessor.PadPkcs1Encryption(data, tmp); + } + + return Interop.AppleCrypto.TryRsaEncryptionPrimitive( + GetKeys().PublicKey, + tmp, + destination, + out bytesWritten); } - else + finally { - Debug.Assert(padding.Mode == RSAEncryptionPaddingMode.Pkcs1); - RsaPaddingProcessor.PadPkcs1Encryption(data, tmp); + CryptographicOperations.ZeroMemory(tmp); + CryptoPool.Return(rented, clearSize: 0); } - - return Interop.AppleCrypto.TryRsaEncryptionPrimitive( - GetKeys().PublicKey, - tmp, - destination, - out bytesWritten); - } - finally - { - CryptographicOperations.ZeroMemory(tmp); - CryptoPool.Return(rented, clearSize: 0); } + + return Interop.AppleCrypto.TryRsaEncrypt( + GetKeys().PublicKey, + data, + destination, + padding, + out bytesWritten); } public override byte[] Decrypt(byte[] data, RSAEncryptionPadding padding) @@ -235,30 +339,7 @@ public override byte[] Decrypt(byte[] data, RSAEncryptionPadding padding) throw new CryptographicException(SR.Cryptography_RSA_DecryptWrongSize); } - if (padding.Mode == RSAEncryptionPaddingMode.Pkcs1) - { - return Interop.AppleCrypto.RsaDecrypt(keys.PrivateKey, data, padding); - } - - int maxOutputSize = RsaPaddingProcessor.BytesRequiredForBitCount(KeySize); - byte[] rented = CryptoPool.Rent(maxOutputSize); - int bytesWritten = 0; - - try - { - if (!TryDecrypt(keys.PrivateKey, data, rented, padding, out bytesWritten)) - { - Debug.Fail($"TryDecrypt returned false with a modulus-sized destination"); - throw new CryptographicException(); - } - - Span contentsSpan = new Span(rented, 0, bytesWritten); - return contentsSpan.ToArray(); - } - finally - { - CryptoPool.Return(rented, bytesWritten); - } + return Interop.AppleCrypto.RsaDecrypt(keys.PrivateKey, data, padding); } public override bool TryDecrypt(ReadOnlySpan data, Span destination, RSAEncryptionPadding padding, out int bytesWritten) @@ -300,35 +381,7 @@ private bool TryDecrypt( throw new CryptographicException(SR.Cryptography_RSA_DecryptWrongSize); } - if (padding.Mode == RSAEncryptionPaddingMode.Pkcs1 || - padding == RSAEncryptionPadding.OaepSHA1) - { - return Interop.AppleCrypto.TryRsaDecrypt(privateKey, data, destination, padding, out bytesWritten); - } - - Debug.Assert(padding.Mode == RSAEncryptionPaddingMode.Oaep); - RsaPaddingProcessor processor = RsaPaddingProcessor.OpenProcessor(padding.OaepHashAlgorithm); - - byte[] rented = CryptoPool.Rent(modulusSizeInBytes); - Span unpaddedData = Span.Empty; - - try - { - if (!Interop.AppleCrypto.TryRsaDecryptionPrimitive(privateKey, data, rented, out int paddedSize)) - { - Debug.Fail($"Raw decryption failed with KeySize={KeySize} and a buffer length {rented.Length}"); - throw new CryptographicException(); - } - - Debug.Assert(modulusSizeInBytes == paddedSize); - unpaddedData = new Span(rented, 0, paddedSize); - return processor.DepadOaep(unpaddedData, destination, out bytesWritten); - } - finally - { - CryptographicOperations.ZeroMemory(unpaddedData); - CryptoPool.Return(rented, clearSize: 0); - } + return Interop.AppleCrypto.TryRsaDecrypt(privateKey, data, destination, padding, out bytesWritten); } public override byte[] SignHash(byte[] hash, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) @@ -665,6 +718,46 @@ private void SetKey(SecKeyPair newKeyPair) } } + private static SafeSecKeyRefHandle ImportKey(RSAParameters parameters) + { + AsnWriter keyWriter; + bool hasPrivateKey; + + if (parameters.D != null) + { + keyWriter = RSAKeyFormatHelper.WritePkcs1PrivateKey(parameters); + hasPrivateKey = true; + } + else + { + keyWriter = RSAKeyFormatHelper.WritePkcs1PublicKey(parameters); + hasPrivateKey = false; + } + + byte[] rented = CryptoPool.Rent(keyWriter.GetEncodedLength()); + + if (!keyWriter.TryEncode(rented, out int written)) + { + Debug.Fail("TryEncode failed with a pre-allocated buffer"); + throw new InvalidOperationException(); + } + + // Explicitly clear the inner buffer + keyWriter.Reset(); + + try + { + return Interop.AppleCrypto.CreateDataKey( + rented.AsSpan(0, written), + Interop.AppleCrypto.PAL_KeyAlgorithm.RSA, + isPublic: !hasPrivateKey); + } + finally + { + CryptoPool.Return(rented, written); + } + } + private static void ValidateParameters(in RSAParameters parameters) { if (parameters.Modulus == null || parameters.Exponent == null) diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSASecurityTransforms.iOS.cs b/src/libraries/Common/src/System/Security/Cryptography/RSASecurityTransforms.iOS.cs index db58a5da3d606..1848139c95cab 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSASecurityTransforms.iOS.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSASecurityTransforms.iOS.cs @@ -17,149 +17,16 @@ internal static partial class RSAImplementation { public sealed partial class RSASecurityTransforms { - public override RSAParameters ExportParameters(bool includePrivateParameters) - { - SecKeyPair keys = GetKeys(); - - if (includePrivateParameters && keys.PrivateKey == null) - { - throw new CryptographicException(SR.Cryptography_OpenInvalidHandle); - } - - byte[] keyBlob = Interop.AppleCrypto.SecKeyCopyExternalRepresentation( - includePrivateParameters ? keys.PrivateKey! : keys.PublicKey); - - try - { - if (!includePrivateParameters) - { - // When exporting a key handle opened from a certificate, it seems to - // export as a PKCS#1 blob instead of an X509 SubjectPublicKeyInfo blob. - // So, check for that. - // NOTE: It doesn't affect macOS Mojave when SecCertificateCopyKey API - // is used. - RSAParameters key; - - AsnReader reader = new AsnReader(keyBlob, AsnEncodingRules.BER); - AsnReader sequenceReader = reader.ReadSequence(); - - if (sequenceReader.PeekTag().Equals(Asn1Tag.Integer)) - { - AlgorithmIdentifierAsn ignored = default; - RSAKeyFormatHelper.ReadRsaPublicKey(keyBlob, ignored, out key); - } - else - { - RSAKeyFormatHelper.ReadSubjectPublicKeyInfo( - keyBlob, - out int localRead, - out key); - Debug.Assert(localRead == keyBlob.Length); - } - return key; - } - else - { - AlgorithmIdentifierAsn ignored = default; - RSAKeyFormatHelper.FromPkcs1PrivateKey( - keyBlob, - ignored, - out RSAParameters key); - return key; - } - } - finally - { - CryptographicOperations.ZeroMemory(keyBlob); - } - } - - public override void ImportParameters(RSAParameters parameters) - { - ValidateParameters(parameters); - ThrowIfDisposed(); - - bool isPrivateKey = parameters.D != null; - - if (isPrivateKey) - { - // Start with the private key, in case some of the private key fields - // don't match the public key fields. - // - // Public import should go off without a hitch. - SafeSecKeyRefHandle privateKey = ImportKey(parameters); - SafeSecKeyRefHandle publicKey = Interop.AppleCrypto.CopyPublicKey(privateKey); - SetKey(SecKeyPair.PublicPrivatePair(publicKey, privateKey)); - } - else - { - SafeSecKeyRefHandle publicKey = ImportKey(parameters); - SetKey(SecKeyPair.PublicOnly(publicKey)); - } - } + private static RSAParameters ExportParametersFromLegacyKey(SecKeyPair keys, bool includePrivateParameters) + => throw new CryptographicException(); - private static SafeSecKeyRefHandle ImportKey(RSAParameters parameters) + private static void ImportPrivateKey( + RSAParameters rsaParameters, + out SafeSecKeyRefHandle privateKey, + out SafeSecKeyRefHandle publicKey) { - AsnWriter keyWriter; - bool hasPrivateKey; - - if (parameters.D != null) - { - keyWriter = RSAKeyFormatHelper.WritePkcs1PrivateKey(parameters); - hasPrivateKey = true; - } - else - { - keyWriter = RSAKeyFormatHelper.WritePkcs1PublicKey(parameters); - hasPrivateKey = false; - } - - byte[] rented = CryptoPool.Rent(keyWriter.GetEncodedLength()); - - if (!keyWriter.TryEncode(rented, out int written)) - { - Debug.Fail("TryEncode failed with a pre-allocated buffer"); - throw new InvalidOperationException(); - } - - // Explicitly clear the inner buffer - keyWriter.Reset(); - - try - { - return Interop.AppleCrypto.CreateDataKey( - rented.AsSpan(0, written), - Interop.AppleCrypto.PAL_KeyAlgorithm.RSA, - isPublic: !hasPrivateKey); - } - finally - { - CryptoPool.Return(rented, written); - } - } - - public override unsafe void ImportRSAPublicKey(ReadOnlySpan source, out int bytesRead) - { - ThrowIfDisposed(); - - fixed (byte* ptr = &MemoryMarshal.GetReference(source)) - { - using (MemoryManager manager = new PointerMemoryManager(ptr, source.Length)) - { - // Validate the DER value and get the number of bytes. - RSAKeyFormatHelper.ReadRsaPublicKey( - manager.Memory, - out int localRead); - - SafeSecKeyRefHandle publicKey = Interop.AppleCrypto.CreateDataKey( - source.Slice(0, localRead), - Interop.AppleCrypto.PAL_KeyAlgorithm.RSA, - isPublic: true); - SetKey(SecKeyPair.PublicOnly(publicKey)); - - bytesRead = localRead; - } - } + privateKey = ImportKey(rsaParameters); + publicKey = Interop.AppleCrypto.CopyPublicKey(privateKey); } } } diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSASecurityTransforms.macOS.cs b/src/libraries/Common/src/System/Security/Cryptography/RSASecurityTransforms.macOS.cs index 9ac208a8ecbaf..8496d3ab2fc0e 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSASecurityTransforms.macOS.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSASecurityTransforms.macOS.cs @@ -17,17 +17,11 @@ internal static partial class RSAImplementation { public sealed partial class RSASecurityTransforms : RSA { - public override RSAParameters ExportParameters(bool includePrivateParameters) + private static RSAParameters ExportParametersFromLegacyKey(SecKeyPair keys, bool includePrivateParameters) { // Apple requires all private keys to be exported encrypted, but since we're trying to export // as parsed structures we will need to decrypt it for the user. const string ExportPassword = "DotnetExportPassphrase"; - SecKeyPair keys = GetKeys(); - - if (includePrivateParameters && keys.PrivateKey == null) - { - throw new CryptographicException(SR.Cryptography_OpenInvalidHandle); - } byte[] keyBlob = Interop.AppleCrypto.SecKeyExport( includePrivateParameters ? keys.PrivateKey : keys.PublicKey, @@ -79,30 +73,33 @@ public override RSAParameters ExportParameters(bool includePrivateParameters) } } - public override void ImportParameters(RSAParameters parameters) - { - ValidateParameters(parameters); - ThrowIfDisposed(); - - bool isPrivateKey = parameters.D != null; + private static bool HasWorkingPKCS1Padding { get; } = OperatingSystem.IsMacOSVersionAtLeast(10, 15); - if (isPrivateKey) + private static void ImportPrivateKey( + RSAParameters rsaParameters, + out SafeSecKeyRefHandle privateKey, + out SafeSecKeyRefHandle publicKey) + { + // macOS 10.14 and older have broken PKCS#1 depadding for decryption + // of empty data. The bug doesn't affect the legacy CSSM keys so we + // use them instead. + if (HasWorkingPKCS1Padding) { - // Start with the private key, in case some of the private key fields - // don't match the public key fields. - // - // Public import should go off without a hitch. - SafeSecKeyRefHandle privateKey = ImportKey(parameters); - - RSAParameters publicOnly = new RSAParameters - { - Modulus = parameters.Modulus, - Exponent = parameters.Exponent, - }; + privateKey = ImportKey(rsaParameters); + publicKey = Interop.AppleCrypto.CopyPublicKey(privateKey); + } + else + { + privateKey = ImportLegacyPrivateKey(rsaParameters); - SafeSecKeyRefHandle publicKey; try { + RSAParameters publicOnly = new RSAParameters + { + Modulus = rsaParameters.Modulus, + Exponent = rsaParameters.Exponent, + }; + publicKey = ImportKey(publicOnly); } catch @@ -110,31 +107,14 @@ public override void ImportParameters(RSAParameters parameters) privateKey.Dispose(); throw; } - - SetKey(SecKeyPair.PublicPrivatePair(publicKey, privateKey)); - } - else - { - SafeSecKeyRefHandle publicKey = ImportKey(parameters); - SetKey(SecKeyPair.PublicOnly(publicKey)); } } - private static SafeSecKeyRefHandle ImportKey(RSAParameters parameters) + private static SafeSecKeyRefHandle ImportLegacyPrivateKey(RSAParameters parameters) { - AsnWriter keyWriter; - bool hasPrivateKey; + Debug.Assert(parameters.D != null); - if (parameters.D != null) - { - keyWriter = RSAKeyFormatHelper.WritePkcs1PrivateKey(parameters); - hasPrivateKey = true; - } - else - { - keyWriter = RSAKeyFormatHelper.WriteSubjectPublicKeyInfo(parameters); - hasPrivateKey = false; - } + AsnWriter keyWriter = RSAKeyFormatHelper.WritePkcs1PrivateKey(parameters); byte[] rented = CryptoPool.Rent(keyWriter.GetEncodedLength()); @@ -149,66 +129,13 @@ private static SafeSecKeyRefHandle ImportKey(RSAParameters parameters) try { - return Interop.AppleCrypto.ImportEphemeralKey(rented.AsSpan(0, written), hasPrivateKey); + return Interop.AppleCrypto.ImportEphemeralKey(rented.AsSpan(0, written), true); } finally { CryptoPool.Return(rented, written); } } - - public override unsafe void ImportSubjectPublicKeyInfo( - ReadOnlySpan source, - out int bytesRead) - { - ThrowIfDisposed(); - - fixed (byte* ptr = &MemoryMarshal.GetReference(source)) - { - using (MemoryManager manager = new PointerMemoryManager(ptr, source.Length)) - { - // Validate the DER value and get the number of bytes. - RSAKeyFormatHelper.ReadSubjectPublicKeyInfo( - manager.Memory, - out int localRead); - - SafeSecKeyRefHandle publicKey = Interop.AppleCrypto.ImportEphemeralKey(source.Slice(0, localRead), false); - SetKey(SecKeyPair.PublicOnly(publicKey)); - - bytesRead = localRead; - } - } - } - - public override unsafe void ImportRSAPublicKey(ReadOnlySpan source, out int bytesRead) - { - ThrowIfDisposed(); - - fixed (byte* ptr = &MemoryMarshal.GetReference(source)) - { - using (MemoryManager manager = new PointerMemoryManager(ptr, source.Length)) - { - AsnReader reader = new AsnReader(manager.Memory, AsnEncodingRules.BER); - ReadOnlyMemory firstElement = reader.PeekEncodedValue(); - - SubjectPublicKeyInfoAsn spki = new SubjectPublicKeyInfoAsn - { - Algorithm = new AlgorithmIdentifierAsn - { - Algorithm = Oids.Rsa, - Parameters = AlgorithmIdentifierAsn.ExplicitDerNull, - }, - SubjectPublicKey = firstElement, - }; - - AsnWriter writer = new AsnWriter(AsnEncodingRules.DER); - spki.Encode(writer); - - ImportSubjectPublicKeyInfo(writer.Encode(), out _); - bytesRead = firstElement.Length; - } - } - } } } } diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native.Apple/entrypoints.c b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Apple/entrypoints.c index 9fa5c5665fef0..d3d524dc07816 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native.Apple/entrypoints.c +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Apple/entrypoints.c @@ -53,7 +53,6 @@ static const Entry s_cryptoAppleNative[] = DllImportEntry(AppleCryptoNative_RsaEncryptOaep) DllImportEntry(AppleCryptoNative_RsaEncryptPkcs) DllImportEntry(AppleCryptoNative_RsaSignaturePrimitive) - DllImportEntry(AppleCryptoNative_RsaDecryptionPrimitive) DllImportEntry(AppleCryptoNative_RsaEncryptionPrimitive) DllImportEntry(AppleCryptoNative_RsaVerificationPrimitive) DllImportEntry(AppleCryptoNative_SecCopyErrorMessageString) diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native.Apple/pal_rsa.c b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Apple/pal_rsa.c index f6a74bd350433..ba2525ffbfa5c 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native.Apple/pal_rsa.c +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Apple/pal_rsa.c @@ -162,13 +162,6 @@ int32_t AppleCryptoNative_RsaSignaturePrimitive( privateKey, pbData, cbData, pDataOut, pErrorOut, kSecKeyAlgorithmRSASignatureRaw, SecKeyCreateSignature); } -int32_t AppleCryptoNative_RsaDecryptionPrimitive( - SecKeyRef privateKey, uint8_t* pbData, int32_t cbData, CFDataRef* pDataOut, CFErrorRef* pErrorOut) -{ - return RsaPrimitive( - privateKey, pbData, cbData, pDataOut, pErrorOut, kSecKeyAlgorithmRSAEncryptionRaw, SecKeyCreateDecryptedData); -} - int32_t AppleCryptoNative_RsaEncryptionPrimitive( SecKeyRef publicKey, uint8_t* pbData, int32_t cbData, CFDataRef* pDataOut, CFErrorRef* pErrorOut) { 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 99829b1809776..fc83d7af8faa9 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 @@ -477,6 +477,8 @@ + - - - pkcs8) if (key is RSAImplementation.RSASecurityTransforms rsa) { - return rsa.GetKeys().PrivateKey; + // Convert data key to legacy CSSM key that can be imported into keychain + byte[] rsaPrivateKey = rsa.ExportRSAPrivateKey(); + using (PinAndClear.Track(rsaPrivateKey)) + { + return Interop.AppleCrypto.ImportEphemeralKey(rsaPrivateKey, true); + } } if (key is DSAImplementation.DSASecurityTransforms dsa) { + // DSA always uses legacy CSSM keys do no need to convert return dsa.GetKeys().PrivateKey; } - return ((ECDsaImplementation.ECDsaSecurityTransforms)key).GetKeys().PrivateKey; + if (key is ECDsaImplementation.ECDsaSecurityTransforms ecdsa) + { + // Convert data key to legacy CSSM key that can be imported into keychain + byte[] ecdsaPrivateKey = ecdsa.ExportECPrivateKey(); + using (PinAndClear.Track(ecdsaPrivateKey)) + { + return Interop.AppleCrypto.ImportEphemeralKey(ecdsaPrivateKey, true); + } + } + + Debug.Fail("Invalid key implementation"); + return null; } } } 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 f11a0661e7315..44505d275b80e 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 @@ -454,6 +454,8 @@ Link="Common\System\Security\Cryptography\RsaPaddingProcessor.cs" /> + - - -