Skip to content

Commit ed16db6

Browse files
committed
Add code path for converting iOS-style keys into CSSM ones
1 parent 87be37c commit ed16db6

1 file changed

Lines changed: 51 additions & 2 deletions

File tree

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/AppleCertificatePal.Keys.macOS.cs

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using System.Text;
1010
using System.Threading;
1111
using Microsoft.Win32.SafeHandles;
12+
using Internal.Cryptography;
1213

1314
namespace System.Security.Cryptography.X509Certificates
1415
{
@@ -57,7 +58,7 @@ public ICertificatePal CopyWithPrivateKey(ECDsa privateKey)
5758

5859
if (typedKey != null)
5960
{
60-
return CopyWithPrivateKey(typedKey.GetKeys().PrivateKey);
61+
return CopyWithPrivateEccKey(typedKey.GetKeys().PrivateKey);
6162
}
6263

6364
byte[] ecPrivateKey = privateKey.ExportECPrivateKey();
@@ -75,7 +76,7 @@ public ICertificatePal CopyWithPrivateKey(ECDiffieHellman privateKey)
7576

7677
if (typedKey != null)
7778
{
78-
return CopyWithPrivateKey(typedKey.GetKeys().PrivateKey);
79+
return CopyWithPrivateEccKey(typedKey.GetKeys().PrivateKey);
7980
}
8081

8182
byte[] ecPrivateKey = privateKey.ExportECPrivateKey();
@@ -105,6 +106,54 @@ public ICertificatePal CopyWithPrivateKey(RSA privateKey)
105106
}
106107
}
107108

109+
private ICertificatePal CopyWithPrivateEccKey(SafeSecKeyRefHandle? privateKey)
110+
{
111+
if (privateKey == null)
112+
{
113+
// Both Windows and Linux/OpenSSL are unaware if they bound a public or private key.
114+
// Here, we do know. So throw if we can't do what they asked.
115+
throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey);
116+
}
117+
118+
// If we succeed in getting the external representation it means it's an iOS-style
119+
// key and we need to convert it to CSSM ephemeral key first.
120+
if (Interop.AppleCrypto.TrySecKeyCopyExternalRepresentation(privateKey, out byte[] keyBlob))
121+
{
122+
using (PinAndClear.Track(keyBlob))
123+
{
124+
AsymmetricAlgorithmHelpers.DecodeFromUncompressedAnsiX963Key(
125+
keyBlob,
126+
true,
127+
out ECParameters ecParameters);
128+
129+
using (PinAndClear.Track(ecParameters.D!))
130+
{
131+
switch (Interop.AppleCrypto.EccGetKeySizeInBits(privateKey))
132+
{
133+
case 256: ecParameters.Curve = ECCurve.NamedCurves.nistP256; break;
134+
case 384: ecParameters.Curve = ECCurve.NamedCurves.nistP384; break;
135+
case 521: ecParameters.Curve = ECCurve.NamedCurves.nistP521; break;
136+
default:
137+
Debug.Fail("Unsupported curve");
138+
throw new CryptographicException();
139+
}
140+
141+
AsnWriter writer = EccKeyFormatHelper.WriteECPrivateKey(ecParameters);
142+
byte[] ecPrivateKey = writer.Encode();
143+
144+
using (PinAndClear.Track(ecPrivateKey))
145+
using (SafeSecKeyRefHandle privateSecKey = Interop.AppleCrypto.ImportEphemeralKey(ecPrivateKey, true))
146+
{
147+
return CopyWithPrivateKey(privateSecKey);
148+
}
149+
}
150+
}
151+
}
152+
153+
// The key is likely legacy CSSM key so we can take the common code path.
154+
return CopyWithPrivateKey(privateKey);
155+
}
156+
108157
private ICertificatePal CopyWithPrivateKey(SafeSecKeyRefHandle? privateKey)
109158
{
110159
if (privateKey == null)

0 commit comments

Comments
 (0)