Skip to content

Commit 2d7eea2

Browse files
committed
Merge in 'release/8.0' changes
2 parents a1a9440 + f381395 commit 2d7eea2

File tree

2 files changed

+107
-1
lines changed
  • src/libraries

2 files changed

+107
-1
lines changed

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

+5-1
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,10 @@ internal static bool TrySecKeyCopyExternalRepresentation(
127127
{
128128
const int errSecPassphraseRequired = -25260;
129129

130+
// macOS Sonoma 14.4 started returning errSecInvalidKeyAttributeMask when a key could not be exported
131+
// because it must be exported with a password.
132+
const int errSecInvalidKeyAttributeMask = -67738;
133+
130134
int result = AppleCryptoNative_SecKeyCopyExternalRepresentation(
131135
key,
132136
out SafeCFDataHandle data,
@@ -141,7 +145,7 @@ internal static bool TrySecKeyCopyExternalRepresentation(
141145
externalRepresentation = CoreFoundation.CFGetData(data);
142146
return true;
143147
case kErrorSeeError:
144-
if (Interop.CoreFoundation.GetErrorCode(errorHandle) == errSecPassphraseRequired)
148+
if (Interop.CoreFoundation.GetErrorCode(errorHandle) is errSecPassphraseRequired or errSecInvalidKeyAttributeMask)
145149
{
146150
externalRepresentation = Array.Empty<byte>();
147151
return false;

src/libraries/System.Security.Cryptography/tests/X509Certificates/CertTests.cs

+102
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,108 @@ public CertTests(ITestOutputHelper output)
2727
_log = output;
2828
}
2929

30+
[Fact]
31+
public static void PrivateKey_FromCertificate_CanExportPrivate_ECDsa()
32+
{
33+
using (ECDsa ca = ECDsa.Create(ECCurve.NamedCurves.nistP256))
34+
{
35+
CertificateRequest req = new("CN=potatos", ca, HashAlgorithmName.SHA256);
36+
37+
using (X509Certificate2 cert = req.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.AddDays(3)))
38+
using (ECDsa certKey = cert.GetECDsaPrivateKey())
39+
{
40+
ECParameters certParameters = certKey.ExportParameters(true);
41+
ECParameters originalParameters = ca.ExportParameters(true);
42+
AssertExtensions.SequenceEqual(originalParameters.D, certParameters.D);
43+
}
44+
}
45+
}
46+
47+
[Fact]
48+
public static void PrivateKey_FromCertificate_CanExportPrivate_RSA()
49+
{
50+
using (RSA ca = RSA.Create(2048))
51+
{
52+
CertificateRequest req = new("CN=potatos", ca, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
53+
54+
using (X509Certificate2 cert = req.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.AddDays(3)))
55+
using (RSA certKey = cert.GetRSAPrivateKey())
56+
{
57+
RSAParameters certParameters = certKey.ExportParameters(true);
58+
RSAParameters originalParameters = ca.ExportParameters(true);
59+
AssertExtensions.SequenceEqual(originalParameters.P, certParameters.P);
60+
AssertExtensions.SequenceEqual(originalParameters.Q, certParameters.Q);
61+
}
62+
}
63+
}
64+
65+
[Fact]
66+
[SkipOnPlatform(PlatformSupport.MobileAppleCrypto, "DSA is not available")]
67+
public static void PrivateKey_FromCertificate_CanExportPrivate_DSA()
68+
{
69+
DSAParameters originalParameters = DSATestData.GetDSA1024Params();
70+
71+
using (DSA ca = DSA.Create())
72+
{
73+
ca.ImportParameters(originalParameters);
74+
DSAX509SignatureGenerator gen = new DSAX509SignatureGenerator(ca);
75+
X500DistinguishedName dn = new X500DistinguishedName("CN=potatos");
76+
77+
CertificateRequest req = new CertificateRequest(
78+
dn,
79+
gen.PublicKey,
80+
HashAlgorithmName.SHA1);
81+
82+
using (X509Certificate2 cert = req.Create(dn, gen, DateTimeOffset.Now, DateTimeOffset.Now.AddDays(3), [1, 2, 3]))
83+
using (X509Certificate2 certWithKey = cert.CopyWithPrivateKey(ca))
84+
using (DSA certKey = certWithKey.GetDSAPrivateKey())
85+
{
86+
DSAParameters certParameters = certKey.ExportParameters(true);
87+
AssertExtensions.SequenceEqual(originalParameters.X, certParameters.X);
88+
}
89+
}
90+
}
91+
92+
[Fact]
93+
public static void PrivateKey_FromCertificate_CanExportPrivate_ECDiffieHellman()
94+
{
95+
using (ECDsa ca = ECDsa.Create(ECCurve.NamedCurves.nistP256))
96+
using (ECDiffieHellman ecdh = ECDiffieHellman.Create(ECCurve.NamedCurves.nistP256))
97+
{
98+
CertificateRequest issuerRequest = new CertificateRequest(
99+
new X500DistinguishedName("CN=root"),
100+
ca,
101+
HashAlgorithmName.SHA256);
102+
103+
issuerRequest.CertificateExtensions.Add(
104+
new X509BasicConstraintsExtension(true, false, 0, true));
105+
106+
CertificateRequest request = new CertificateRequest(
107+
new X500DistinguishedName("CN=potato"),
108+
new PublicKey(ecdh),
109+
HashAlgorithmName.SHA256);
110+
111+
request.CertificateExtensions.Add(
112+
new X509BasicConstraintsExtension(false, false, 0, true));
113+
request.CertificateExtensions.Add(
114+
new X509KeyUsageExtension(X509KeyUsageFlags.KeyAgreement, true));
115+
116+
DateTimeOffset notBefore = DateTimeOffset.UtcNow;
117+
DateTimeOffset notAfter = notBefore.AddDays(30);
118+
byte[] serial = [1, 2, 3, 4, 5, 6, 7, 8];
119+
120+
using (X509Certificate2 issuer = issuerRequest.CreateSelfSigned(notBefore, notAfter))
121+
using (X509Certificate2 cert = request.Create(issuer, notBefore, notAfter, serial))
122+
using (X509Certificate2 certWithKey = cert.CopyWithPrivateKey(ecdh))
123+
using (ECDiffieHellman certKey = certWithKey.GetECDiffieHellmanPrivateKey())
124+
{
125+
ECParameters certParameters = certKey.ExportParameters(true);
126+
ECParameters originalParameters = ecdh.ExportParameters(true);
127+
AssertExtensions.SequenceEqual(originalParameters.D, certParameters.D);
128+
}
129+
}
130+
}
131+
30132
[Fact]
31133
public static void PublicPrivateKey_IndependentLifetimes_ECDsa()
32134
{

0 commit comments

Comments
 (0)