Skip to content

Commit 04d2618

Browse files
committed
Use data keys on macOS for RSA, EC cryptography
1 parent 6a5bc53 commit 04d2618

File tree

15 files changed

+500
-733
lines changed

15 files changed

+500
-733
lines changed

src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.RSA.cs

-24
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,6 @@ private static extern int AppleCryptoNative_RsaVerificationPrimitive(
3535
out SafeCFDataHandle pDataOut,
3636
out SafeCFErrorHandle pErrorOut);
3737

38-
[DllImport(Libraries.AppleCryptoNative)]
39-
private static extern int AppleCryptoNative_RsaDecryptionPrimitive(
40-
SafeSecKeyRefHandle privateKey,
41-
ref byte pbData,
42-
int cbData,
43-
out SafeCFDataHandle pDataOut,
44-
out SafeCFErrorHandle pErrorOut);
45-
4638
[DllImport(Libraries.AppleCryptoNative)]
4739
private static extern int AppleCryptoNative_RsaEncryptionPrimitive(
4840
SafeSecKeyRefHandle publicKey,
@@ -270,22 +262,6 @@ private static bool ProcessPrimitiveResponse(
270262
throw new CryptographicException();
271263
}
272264

273-
internal static bool TryRsaDecryptionPrimitive(
274-
SafeSecKeyRefHandle privateKey,
275-
ReadOnlySpan<byte> source,
276-
Span<byte> destination,
277-
out int bytesWritten)
278-
{
279-
int returnValue = AppleCryptoNative_RsaDecryptionPrimitive(
280-
privateKey,
281-
ref MemoryMarshal.GetReference(source),
282-
source.Length,
283-
out SafeCFDataHandle cfData,
284-
out SafeCFErrorHandle cfError);
285-
286-
return ProcessPrimitiveResponse(returnValue, cfData, cfError, destination, out bytesWritten);
287-
}
288-
289265
internal static bool TryRsaEncryptionPrimitive(
290266
SafeSecKeyRefHandle publicKey,
291267
ReadOnlySpan<byte> source,

src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.SecKeyRef.cs

+89
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@ internal static partial class AppleCrypto
1616
private const int kErrorSeeError = -2;
1717
private const int kPlatformNotSupported = -5;
1818

19+
internal enum PAL_KeyAlgorithm : uint
20+
{
21+
Unknown = 0,
22+
EC = 1,
23+
RSA = 2,
24+
}
25+
1926
[DllImport(Libraries.AppleCryptoNative)]
2027
private static extern ulong AppleCryptoNative_SecKeyGetSimpleKeySizeInBytes(SafeSecKeyRefHandle publicKey);
2128

@@ -82,6 +89,88 @@ internal static int GetSimpleKeySizeInBits(SafeSecKeyRefHandle publicKey)
8289
return (int)(keySizeInBytes * 8);
8390
}
8491
}
92+
93+
internal static unsafe SafeSecKeyRefHandle CreateDataKey(
94+
ReadOnlySpan<byte> keyData,
95+
PAL_KeyAlgorithm keyAlgorithm,
96+
bool isPublic)
97+
{
98+
fixed (byte* pKey = keyData)
99+
{
100+
int result = AppleCryptoNative_SecKeyCreateWithData(
101+
pKey,
102+
keyData.Length,
103+
keyAlgorithm,
104+
isPublic ? 1 : 0,
105+
out SafeSecKeyRefHandle dataKey,
106+
out SafeCFErrorHandle errorHandle);
107+
108+
using (errorHandle)
109+
{
110+
switch (result)
111+
{
112+
case kSuccess:
113+
return dataKey;
114+
case kErrorSeeError:
115+
throw CreateExceptionForCFError(errorHandle);
116+
default:
117+
Debug.Fail($"SecKeyCreateWithData returned {result}");
118+
throw new CryptographicException();
119+
}
120+
}
121+
}
122+
}
123+
124+
internal static bool TrySecKeyCopyExternalRepresentation(
125+
SafeSecKeyRefHandle key,
126+
out byte[] externalRepresentation)
127+
{
128+
const int errSecPassphraseRequired = -25260;
129+
130+
int result = AppleCryptoNative_SecKeyCopyExternalRepresentation(
131+
key,
132+
out SafeCFDataHandle data,
133+
out SafeCFErrorHandle errorHandle);
134+
135+
using (errorHandle)
136+
using (data)
137+
{
138+
switch (result)
139+
{
140+
case kSuccess:
141+
externalRepresentation = CoreFoundation.CFGetData(data);
142+
return true;
143+
case kErrorSeeError:
144+
if (Interop.CoreFoundation.GetErrorCode(errorHandle) == errSecPassphraseRequired)
145+
{
146+
externalRepresentation = Array.Empty<byte>();
147+
return false;
148+
}
149+
throw CreateExceptionForCFError(errorHandle);
150+
default:
151+
Debug.Fail($"SecKeyCopyExternalRepresentation returned {result}");
152+
throw new CryptographicException();
153+
}
154+
}
155+
}
156+
157+
[DllImport(Libraries.AppleCryptoNative)]
158+
private static unsafe extern int AppleCryptoNative_SecKeyCreateWithData(
159+
byte* pKey,
160+
int cbKey,
161+
PAL_KeyAlgorithm keyAlgorithm,
162+
int isPublic,
163+
out SafeSecKeyRefHandle pDataKey,
164+
out SafeCFErrorHandle pErrorOut);
165+
166+
[DllImport(Libraries.AppleCryptoNative)]
167+
private static unsafe extern int AppleCryptoNative_SecKeyCopyExternalRepresentation(
168+
SafeSecKeyRefHandle key,
169+
out SafeCFDataHandle pDataOut,
170+
out SafeCFErrorHandle pErrorOut);
171+
172+
[DllImport(Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_SecKeyCopyPublicKey")]
173+
internal static unsafe extern SafeSecKeyRefHandle CopyPublicKey(SafeSecKeyRefHandle privateKey);
85174
}
86175
}
87176

src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.SecKeyRef.iOS.cs

-95
This file was deleted.

src/libraries/Common/src/System/Security/Cryptography/EccSecurityTransforms.cs

+124
Original file line numberDiff line numberDiff line change
@@ -116,11 +116,135 @@ private void SetKey(SecKeyPair keyPair)
116116
current?.Dispose();
117117
}
118118

119+
internal ECParameters ExportParameters(bool includePrivateParameters, int keySizeInBits)
120+
{
121+
SecKeyPair keys = GetOrGenerateKeys(keySizeInBits);
122+
123+
if (includePrivateParameters && keys.PrivateKey == null)
124+
{
125+
throw new CryptographicException(SR.Cryptography_OpenInvalidHandle);
126+
}
127+
128+
bool gotKeyBlob = Interop.AppleCrypto.TrySecKeyCopyExternalRepresentation(
129+
includePrivateParameters ? keys.PrivateKey! : keys.PublicKey,
130+
out byte[] keyBlob);
131+
132+
if (!gotKeyBlob)
133+
{
134+
return ExportParametersFromLegacyKey(keys, includePrivateParameters);
135+
}
136+
137+
try
138+
{
139+
AsymmetricAlgorithmHelpers.DecodeFromUncompressedAnsiX963Key(
140+
keyBlob,
141+
includePrivateParameters,
142+
out ECParameters key);
143+
144+
switch (GetKeySize(keys))
145+
{
146+
case 256: key.Curve = ECCurve.NamedCurves.nistP256; break;
147+
case 384: key.Curve = ECCurve.NamedCurves.nistP384; break;
148+
case 521: key.Curve = ECCurve.NamedCurves.nistP521; break;
149+
default:
150+
Debug.Fail("Unsupported curve");
151+
throw new CryptographicException();
152+
}
153+
154+
return key;
155+
}
156+
finally
157+
{
158+
CryptographicOperations.ZeroMemory(keyBlob);
159+
}
160+
}
161+
162+
internal int ImportParameters(ECParameters parameters)
163+
{
164+
parameters.Validate();
165+
ThrowIfDisposed();
166+
167+
if (!parameters.Curve.IsNamed)
168+
{
169+
throw new PlatformNotSupportedException(SR.Cryptography_ECC_NamedCurvesOnly);
170+
}
171+
172+
switch (parameters.Curve.Oid.Value)
173+
{
174+
case Oids.secp256r1:
175+
case Oids.secp384r1:
176+
case Oids.secp521r1:
177+
break;
178+
default:
179+
throw new PlatformNotSupportedException(
180+
SR.Format(SR.Cryptography_CurveNotSupported, parameters.Curve.Oid.Value ?? parameters.Curve.Oid.FriendlyName));
181+
}
182+
183+
if (parameters.Q.X == null || parameters.Q.Y == null)
184+
{
185+
ExtractPublicKeyFromPrivateKey(ref parameters);
186+
}
187+
188+
bool isPrivateKey = parameters.D != null;
189+
SecKeyPair newKeys;
190+
191+
if (isPrivateKey)
192+
{
193+
// Start with the private key, in case some of the private key fields don't
194+
// match the public key fields and the system determines an integrity failure.
195+
//
196+
// Public import should go off without a hitch.
197+
SafeSecKeyRefHandle privateKey = ImportKey(parameters);
198+
SafeSecKeyRefHandle publicKey = Interop.AppleCrypto.CopyPublicKey(privateKey);
199+
newKeys = SecKeyPair.PublicPrivatePair(publicKey, privateKey);
200+
}
201+
else
202+
{
203+
SafeSecKeyRefHandle publicKey = ImportKey(parameters);
204+
newKeys = SecKeyPair.PublicOnly(publicKey);
205+
}
206+
207+
int size = GetKeySize(newKeys);
208+
SetKey(newKeys);
209+
210+
return size;
211+
}
212+
119213
private static int GetKeySize(SecKeyPair newKeys)
120214
{
121215
long size = Interop.AppleCrypto.EccGetKeySizeInBits(newKeys.PublicKey);
122216
Debug.Assert(size == 256 || size == 384 || size == 521, $"Unknown keysize ({size})");
123217
return (int)size;
124218
}
219+
220+
private static SafeSecKeyRefHandle ImportKey(ECParameters parameters)
221+
{
222+
int fieldSize = parameters.Q!.X!.Length;
223+
224+
Debug.Assert(parameters.Q.Y != null && parameters.Q.Y.Length == fieldSize);
225+
Debug.Assert(parameters.Q.X != null && parameters.Q.X.Length == fieldSize);
226+
227+
int keySize = 1 + fieldSize * (parameters.D != null ? 3 : 2);
228+
byte[] dataKeyPool = CryptoPool.Rent(keySize);
229+
Span<byte> dataKey = dataKeyPool.AsSpan(0, keySize);
230+
231+
try
232+
{
233+
AsymmetricAlgorithmHelpers.EncodeToUncompressedAnsiX963Key(
234+
parameters.Q.X,
235+
parameters.Q.Y,
236+
parameters.D,
237+
dataKey);
238+
239+
return Interop.AppleCrypto.CreateDataKey(
240+
dataKey,
241+
Interop.AppleCrypto.PAL_KeyAlgorithm.EC,
242+
isPublic: parameters.D == null);
243+
}
244+
finally
245+
{
246+
CryptoPool.Return(dataKeyPool, keySize);
247+
}
248+
}
125249
}
126250
}

0 commit comments

Comments
 (0)