99using System . Text ;
1010using System . Threading ;
1111using Microsoft . Win32 . SafeHandles ;
12+ using Internal . Cryptography ;
1213
1314namespace 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