Exemplo n.º 1
0
        private ICertificatePal CopyWithPrivateKey(SecKeyPair keyPair)
        {
            if (keyPair.PrivateKey == null)
            {
                // Both Windows and Linux/OpenSSL are unaware if they bound a public or private key.
                // Here, we do know.  So throw if we can't do what they asked.
                throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey);
            }

            SafeKeychainHandle keychain = Interop.AppleCrypto.SecKeychainItemCopyKeychain(keyPair.PrivateKey);

            if (keychain.IsInvalid)
            {
                keychain = Interop.AppleCrypto.CreateTemporaryKeychain();
            }

            using (keychain)
            {
                SafeSecIdentityHandle identityHandle = Interop.AppleCrypto.X509CopyWithPrivateKey(
                    _certHandle,
                    keyPair.PrivateKey,
                    keychain);

                AppleCertificatePal newPal = new AppleCertificatePal(identityHandle);
                newPal.HoldPrivateKey();
                return(newPal);
            }
        }
Exemplo n.º 2
0
            public X509ContentType GetCertContentType(ReadOnlySpan <byte> rawData)
            {
                const int errSecUnknownFormat = -25257;

                if (rawData == null || rawData.Length == 0)
                {
                    // Throw to match Windows and Unix behavior.
                    throw Interop.AppleCrypto.CreateExceptionForOSStatus(errSecUnknownFormat);
                }

                X509ContentType result = X509ContentType.Unknown;

                AppleCertificatePal.TryDecodePem(
                    rawData,
                    (derData, contentType) =>
                {
                    result = contentType;
                    return(false);
                });

                if (result == X509ContentType.Unknown)
                {
                    result = AppleCertificatePal.GetDerCertContentType(rawData);
                }

                if (result == X509ContentType.Unknown)
                {
                    // Throw to match Windows and Unix behavior.
                    throw Interop.AppleCrypto.CreateExceptionForOSStatus(errSecUnknownFormat);
                }

                return(result);
            }
Exemplo n.º 3
0
        internal static AppleCertificatePal ImportPkcs12(UnixPkcs12Reader.CertAndKey certAndKey)
        {
            AppleCertificatePal pal = (AppleCertificatePal)certAndKey.Cert !;

            if (certAndKey.Key != null)
            {
                AppleCertificateExporter exporter = new AppleCertificateExporter(new TempExportPal(pal), certAndKey.Key);
                byte[] smallPfx = exporter.Export(X509ContentType.Pkcs12, s_passwordExportHandle) !;

                SafeSecIdentityHandle    identityHandle;
                SafeSecCertificateHandle certHandle = Interop.AppleCrypto.X509ImportCertificate(
                    smallPfx,
                    X509ContentType.Pkcs12,
                    s_passwordExportHandle,
                    out identityHandle);

                if (identityHandle.IsInvalid)
                {
                    identityHandle.Dispose();
                    return(new AppleCertificatePal(certHandle));
                }

                certHandle.Dispose();
                return(new AppleCertificatePal(identityHandle));
            }

            return(pal);
        }
        internal static ICertificatePal ImportPkcs12NonExportable(
            AppleCertificatePal cert,
            SafeSecKeyRefHandle privateKey,
            SafePasswordHandle password,
            SafeKeychainHandle keychain)
        {
            Pkcs12SmallExport exporter = new Pkcs12SmallExport(new TempExportPal(cert), privateKey);

            byte[] smallPfx = exporter.Export(X509ContentType.Pkcs12, password) !;

            SafeSecIdentityHandle    identityHandle;
            SafeSecCertificateHandle certHandle = Interop.AppleCrypto.X509ImportCertificate(
                smallPfx,
                X509ContentType.Pkcs12,
                password,
                keychain,
                exportable: false,
                out identityHandle);

            // On Windows and Linux if a PFX uses a LocalKeyId to bind the wrong key to a cert, the
            // nonsensical object of "this cert, that key" is returned.
            //
            // On macOS, because we can't forge CFIdentityRefs without the keychain, we're subject to
            // Apple's more stringent matching of a consistent keypair.
            if (identityHandle.IsInvalid)
            {
                identityHandle.Dispose();
                return(new AppleCertificatePal(certHandle));
            }

            certHandle.Dispose();
            return(new AppleCertificatePal(identityHandle));
        }
Exemplo n.º 5
0
 public static ICertificatePal FromBlob(
     ReadOnlySpan <byte> rawData,
     SafePasswordHandle password,
     X509KeyStorageFlags keyStorageFlags)
 {
     return(AppleCertificatePal.FromBlob(rawData, password, keyStorageFlags));
 }
Exemplo n.º 6
0
            public void MoveTo(X509Certificate2Collection collection)
            {
                foreach (UnixPkcs12Reader.CertAndKey certAndKey in _pkcs12.EnumerateAll())
                {
                    AppleCertificatePal pal = (AppleCertificatePal)certAndKey.Cert !;
                    SafeSecKeyRefHandle?safeSecKeyRefHandle =
                        ApplePkcs12Reader.GetPrivateKey(certAndKey.Key);

                    using (safeSecKeyRefHandle)
                    {
                        ICertificatePal newPal;

                        // SecItemImport doesn't seem to respect non-exportable import for PKCS#8,
                        // only PKCS#12.
                        //
                        // So, as part of reading this PKCS#12 we now need to write the minimum
                        // PKCS#12 in a normalized form, and ask the OS to import it.
                        if (!_exportable && safeSecKeyRefHandle != null)
                        {
                            newPal = AppleCertificatePal.ImportPkcs12NonExportable(
                                pal,
                                safeSecKeyRefHandle,
                                _password,
                                _keychain);
                        }
                        else
                        {
                            newPal = pal.MoveToKeychain(_keychain, safeSecKeyRefHandle) ?? pal;
                        }

                        X509Certificate2 cert = new X509Certificate2(newPal);
                        collection.Add(cert);
                    }
                }
            }
Exemplo n.º 7
0
 public void MoveTo(X509Certificate2Collection collection)
 {
     foreach (UnixPkcs12Reader.CertAndKey certAndKey in _pkcs12.EnumerateAll())
     {
         collection.Add(new X509Certificate2(AppleCertificatePal.ImportPkcs12(certAndKey)));
     }
 }
Exemplo n.º 8
0
            private static SafeSecKeyRefHandle DecodeECPublicKey(ICertificatePal?certificatePal)
            {
                const int errSecInvalidKeyRef      = -67712;
                const int errSecUnsupportedKeySize = -67735;

                if (certificatePal is null)
                {
                    throw new NotSupportedException(SR.NotSupported_KeyAlgorithm);
                }

                AppleCertificatePal applePal = (AppleCertificatePal)certificatePal;
                SafeSecKeyRefHandle key      = Interop.AppleCrypto.X509GetPublicKey(applePal.CertificateHandle);

                // If X509GetPublicKey uses the new SecCertificateCopyKey API it can return an invalid
                // key reference for unsupported algorithms. This currently happens for the BrainpoolP160r1
                // algorithm in the test suite (as of macOS Mojave Developer Preview 4).
                if (key.IsInvalid)
                {
                    throw Interop.AppleCrypto.CreateExceptionForOSStatus(errSecInvalidKeyRef);
                }
                // EccGetKeySizeInBits can fail for two reasons. First, the Apple implementation has changed
                // and we receive values from API that were not previously handled. In that case the
                // implementation will need to be adjusted to handle these values. Second, we deliberately
                // return 0 from the native code to prevent hitting buggy API implementations in Apple code
                // later.
                if (Interop.AppleCrypto.EccGetKeySizeInBits(key) == 0)
                {
                    key.Dispose();
                    throw Interop.AppleCrypto.CreateExceptionForOSStatus(errSecUnsupportedKeySize);
                }

                return(key);
            }
Exemplo n.º 9
0
            public void Remove(ICertificatePal cert)
            {
                AppleCertificatePal applePal = (AppleCertificatePal)cert;

                var handle = (SafeKeychainItemHandle?)applePal.IdentityHandle ?? applePal.CertificateHandle;

                Interop.AppleCrypto.X509StoreRemoveCertificate(handle, _keychainHandle, _readonly);
            }
Exemplo n.º 10
0
        private SafeCreateHandle PrepareCertsArray(ICertificatePal cert, X509Certificate2Collection extraStore)
        {
            IntPtr[]     ptrs        = new IntPtr[1 + (extraStore?.Count ?? 0)];
            SafeHandle[] safeHandles = new SafeHandle[ptrs.Length];

            AppleCertificatePal applePal = (AppleCertificatePal)cert;

            safeHandles[0] = applePal.CertificateHandle;

            if (extraStore != null)
            {
                for (int i = 0; i < extraStore.Count; i++)
                {
                    AppleCertificatePal extraCertPal = (AppleCertificatePal)extraStore[i].Pal;

                    safeHandles[i + 1] = extraCertPal.CertificateHandle;
                }
            }

            int  idx      = 0;
            bool addedRef = false;

            try
            {
                for (idx = 0; idx < safeHandles.Length; idx++)
                {
                    SafeHandle handle = safeHandles[idx];
                    handle.DangerousAddRef(ref addedRef);
                    ptrs[idx] = handle.DangerousGetHandle();
                }
            }
            catch
            {
                // If any DangerousAddRef failed, idx will be on the one that failed, so we'll start off
                // by subtracing one.
                for (idx--; idx >= 0; idx--)
                {
                    safeHandles[idx].DangerousRelease();
                }

                throw;
            }

            // Creating the array has the effect of calling CFRetain() on all of the pointers, so the native
            // resource is safe even if we DangerousRelease=>ReleaseHandle them.
            SafeCreateHandle certsArray = Interop.CoreFoundation.CFArrayCreate(ptrs, (UIntPtr)ptrs.Length);

            _extraHandles.Push(certsArray);

            for (idx = 0; idx < safeHandles.Length; idx++)
            {
                safeHandles[idx].DangerousRelease();
            }

            return(certsArray);
        }
            public void Remove(ICertificatePal cert)
            {
                if (_readonly)
                {
                    throw new CryptographicException(SR.Cryptography_X509_StoreReadOnly);
                }

                AppleCertificatePal applePal = (AppleCertificatePal)cert;

                Interop.AppleCrypto.X509StoreRemoveCertificate(applePal.CertificateHandle, _keychainHandle);
            }
Exemplo n.º 12
0
            public void Add(ICertificatePal cert)
            {
                if (_readonly)
                {
                    throw new CryptographicException(SR.Cryptography_X509_StoreReadOnly);
                }

                AppleCertificatePal applePal = (AppleCertificatePal)cert;

                var handle = (SafeKeychainItemHandle?)applePal.IdentityHandle ?? applePal.CertificateHandle;

                Interop.AppleCrypto.X509StoreAddCertificate(handle, _keychainHandle);
            }
        private static ICertificatePal ImportPkcs12(
            byte[] rawData,
            SafePasswordHandle password,
            bool exportable,
            SafeKeychainHandle keychain)
        {
            using (ApplePkcs12Reader reader = new ApplePkcs12Reader(rawData))
            {
                reader.Decrypt(password);

                UnixPkcs12Reader.CertAndKey certAndKey = reader.GetSingleCert();
                AppleCertificatePal         pal        = (AppleCertificatePal)certAndKey.Cert !;

                SafeSecKeyRefHandle?safeSecKeyRefHandle =
                    ApplePkcs12Reader.GetPrivateKey(certAndKey.Key);

                AppleCertificatePal?newPal;

                using (safeSecKeyRefHandle)
                {
                    // SecItemImport doesn't seem to respect non-exportable import for PKCS#8,
                    // only PKCS#12.
                    //
                    // So, as part of reading this PKCS#12 we now need to write the minimum
                    // PKCS#12 in a normalized form, and ask the OS to import it.
                    if (!exportable && safeSecKeyRefHandle != null)
                    {
                        using (pal)
                        {
                            return(ImportPkcs12NonExportable(pal, safeSecKeyRefHandle, password, keychain));
                        }
                    }

                    newPal = pal.MoveToKeychain(keychain, safeSecKeyRefHandle);

                    if (newPal != null)
                    {
                        pal.Dispose();
                    }
                }

                // If no new PAL came back, it means we moved the cert, but had no private key.
                return(newPal ?? pal);
            }
        }
Exemplo n.º 14
0
            protected override byte[] ExportPkcs7()
            {
                IntPtr[] certHandles;

                if (_singleCertPal != null)
                {
                    certHandles = new[] { ((AppleCertificatePal)_singleCertPal).CertificateHandle.DangerousGetHandle() };
                }
                else if (_certs !.Count > 0)
                {
                    certHandles = new IntPtr[_certs.Count];

                    for (int i = 0; i < _certs.Count; i++)
                    {
                        AppleCertificatePal pal = (AppleCertificatePal)_certs[i].Pal;
                        certHandles[i] = pal.CertificateHandle.DangerousGetHandle();
                    }
                }
Exemplo n.º 15
0
            public AsymmetricAlgorithm DecodePublicKey(Oid oid, byte[] encodedKeyValue, byte[] encodedParameters,
                                                       ICertificatePal certificatePal)
            {
                AppleCertificatePal applePal = certificatePal as AppleCertificatePal;

                if (applePal != null)
                {
                    SafeSecKeyRefHandle key = Interop.AppleCrypto.X509GetPublicKey(applePal.CertificateHandle);

                    switch (oid.Value)
                    {
                    case Oids.RsaRsa:
                        return(new RSAImplementation.RSASecurityTransforms(key));

                    case Oids.DsaDsa:
                        if (key.IsInvalid)
                        {
                            // SecCertificateCopyKey returns null for DSA, so fall back to manually building it.
                            return(DecodeDsaPublicKey(encodedKeyValue, encodedParameters));
                        }
                        return(new DSAImplementation.DSASecurityTransforms(key));

                    case Oids.Ecc:
                        return(new ECDsaImplementation.ECDsaSecurityTransforms(key));
                    }

                    key.Dispose();
                }
                else
                {
                    switch (oid.Value)
                    {
                    case Oids.RsaRsa:
                        return(DecodeRsaPublicKey(encodedKeyValue));

                    case Oids.DsaDsa:
                        return(DecodeDsaPublicKey(encodedKeyValue, encodedParameters));
                    }
                }

                throw new NotSupportedException(SR.NotSupported_KeyAlgorithm);
            }
Exemplo n.º 16
0
            private byte[] ExportPkcs7()
            {
                IntPtr[] certHandles;

                if (_singleCertPal != null)
                {
                    certHandles = new[] { ((AppleCertificatePal)_singleCertPal).CertificateHandle.DangerousGetHandle() };
                }
                else
                {
                    certHandles = new IntPtr[_certs.Count];

                    for (int i = 0; i < _certs.Count; i++)
                    {
                        AppleCertificatePal pal = (AppleCertificatePal)_certs[i].Pal;
                        certHandles[i] = pal.CertificateHandle.DangerousGetHandle();
                    }
                }

                return(Interop.AppleCrypto.X509ExportPkcs7(certHandles));
            }
Exemplo n.º 17
0
            protected override byte[] ExportPkcs8(ICertificatePalCore certificatePal, ReadOnlySpan <char> password)
            {
                AppleCertificatePal pal = (AppleCertificatePal)certificatePal;

                return(pal.ExportPkcs8(password));
            }
Exemplo n.º 18
0
        private ICertificatePal CopyWithPrivateKey(SecKeyPair keyPair)
        {
            if (keyPair.PrivateKey == null)
            {
                // Both Windows and Linux/OpenSSL are unaware if they bound a public or private key.
                // Here, we do know.  So throw if we can't do what they asked.
                throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey);
            }

            SafeKeychainHandle keychain = Interop.AppleCrypto.SecKeychainItemCopyKeychain(keyPair.PrivateKey);

            // If we're using a key already in a keychain don't add the certificate to that keychain here,
            // do it in the temporary add/remove in the shim.
            SafeKeychainHandle cloneKeychain = SafeTemporaryKeychainHandle.InvalidHandle;

            if (keychain.IsInvalid)
            {
                keychain      = Interop.AppleCrypto.CreateTemporaryKeychain();
                cloneKeychain = keychain;
            }

            // Because SecIdentityRef only has private constructors we need to have the cert and the key
            // in the same keychain.  That almost certainly means we're going to need to add this cert to a
            // keychain, and when a cert that isn't part of a keychain gets added to a keychain then the
            // interior pointer of "what keychain did I come from?" used by SecKeychainItemCopyKeychain gets
            // set. That makes this function have side effects, which is not desired.
            //
            // It also makes reference tracking on temporary keychains broken, since the cert can
            // DangerousRelease a handle it didn't DangerousAddRef on.  And so CopyWithPrivateKey makes
            // a temporary keychain, then deletes it before anyone has a chance to (e.g.) export the
            // new identity as a PKCS#12 blob.
            //
            // Solution: Clone the cert, like we do in Windows.
            SafeSecCertificateHandle tempHandle;

            {
                byte[]                export     = RawData;
                const bool            exportable = false;
                SafeSecIdentityHandle identityHandle;
                tempHandle = Interop.AppleCrypto.X509ImportCertificate(
                    export,
                    X509ContentType.Cert,
                    SafePasswordHandle.InvalidHandle,
                    cloneKeychain,
                    exportable,
                    out identityHandle);

                Debug.Assert(identityHandle.IsInvalid, "identityHandle should be IsInvalid");
                identityHandle.Dispose();

                Debug.Assert(!tempHandle.IsInvalid, "tempHandle should not be IsInvalid");
            }

            using (keychain)
                using (tempHandle)
                {
                    SafeSecIdentityHandle identityHandle = Interop.AppleCrypto.X509CopyWithPrivateKey(
                        tempHandle,
                        keyPair.PrivateKey,
                        keychain);

                    AppleCertificatePal newPal = new AppleCertificatePal(identityHandle);
                    return(newPal);
                }
        }
        public static ICertificatePal FromBlob(
            ReadOnlySpan <byte> rawData,
            SafePasswordHandle password,
            X509KeyStorageFlags keyStorageFlags)
        {
            Debug.Assert(password != null);

            X509ContentType contentType = X509Certificate2.GetCertContentType(rawData);

            if (contentType == X509ContentType.Pkcs7)
            {
                // In single mode for a PKCS#7 signed or signed-and-enveloped file we're supposed to return
                // the certificate which signed the PKCS#7 file.
                //
                // X509Certificate2Collection::Export(X509ContentType.Pkcs7) claims to be a signed PKCS#7,
                // but doesn't emit a signature block. So this is hard to test.
                //
                // TODO(2910): Figure out how to extract the signing certificate, when it's present.
                throw new CryptographicException(SR.Cryptography_X509_PKCS7_NoSigner);
            }

            if (contentType == X509ContentType.Pkcs12)
            {
                if ((keyStorageFlags & X509KeyStorageFlags.EphemeralKeySet) == X509KeyStorageFlags.EphemeralKeySet)
                {
                    throw new PlatformNotSupportedException(SR.Cryptography_X509_NoEphemeralPfx);
                }

                bool exportable = (keyStorageFlags & X509KeyStorageFlags.Exportable) == X509KeyStorageFlags.Exportable;

                bool persist =
                    (keyStorageFlags & X509KeyStorageFlags.PersistKeySet) == X509KeyStorageFlags.PersistKeySet;

                SafeKeychainHandle keychain = persist
                    ? Interop.AppleCrypto.SecKeychainCopyDefault()
                    : Interop.AppleCrypto.CreateTemporaryKeychain();

                using (keychain)
                {
                    AppleCertificatePal ret = ImportPkcs12(rawData, password, exportable, keychain);
                    if (!persist)
                    {
                        // If we used temporary keychain we need to prevent deletion.
                        // on 10.15+ if keychain is unlinked, certain certificate operations may fail.
                        bool success = false;
                        keychain.DangerousAddRef(ref success);
                        if (success)
                        {
                            ret._tempKeychain = keychain;
                        }
                    }

                    return(ret);
                }
            }

            SafeSecIdentityHandle    identityHandle;
            SafeSecCertificateHandle certHandle = Interop.AppleCrypto.X509ImportCertificate(
                rawData,
                contentType,
                SafePasswordHandle.InvalidHandle,
                SafeTemporaryKeychainHandle.InvalidHandle,
                exportable: true,
                out identityHandle);

            if (identityHandle.IsInvalid)
            {
                identityHandle.Dispose();
                return(new AppleCertificatePal(certHandle));
            }

            Debug.Fail("Non-PKCS12 import produced an identity handle");

            identityHandle.Dispose();
            certHandle.Dispose();
            throw new CryptographicException();
        }
Exemplo n.º 20
0
 internal static ICertificatePal?FromHandle(IntPtr handle, bool throwOnFail)
 {
     return(AppleCertificatePal.FromHandle(handle, throwOnFail));
 }
Exemplo n.º 21
0
 public static ICertificatePal?FromOtherCert(X509Certificate cert)
 {
     return(AppleCertificatePal.FromOtherCert(cert));
 }
 internal TempExportPal(AppleCertificatePal realPal)
 {
     _realPal = realPal;
 }
 protected override byte[] ExportPkcs8(ICertificatePalCore certificatePal, ReadOnlySpan <char> password)
 {
     return(AppleCertificatePal.ExportPkcs8(_privateKey, password));
 }
Exemplo n.º 24
0
 public static ICertificatePal FromFile(string fileName, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags)
 {
     return(AppleCertificatePal.FromFile(fileName, password, keyStorageFlags));
 }
Exemplo n.º 25
0
        public static ILoaderPal FromBlob(ReadOnlySpan <byte> rawData, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags)
        {
            List <ICertificatePal>?certificateList = null;

            AppleCertificatePal.TryDecodePem(
                rawData,
                (derData, contentType) =>
            {
                certificateList = certificateList ?? new List <ICertificatePal>();
                certificateList.Add(AppleCertificatePal.FromDerBlob(derData, contentType, password, keyStorageFlags));
                return(true);
            });

            if (certificateList != null)
            {
                return(new CertCollectionLoader(certificateList));
            }

            X509ContentType contentType = AppleCertificatePal.GetDerCertContentType(rawData);

            if (contentType == X509ContentType.Pkcs7)
            {
                throw new CryptographicException(
                          SR.Cryptography_X509_PKCS7_Unsupported,
                          new PlatformNotSupportedException(SR.Cryptography_X509_PKCS7_Unsupported));
            }

            if (contentType == X509ContentType.Pkcs12)
            {
                ApplePkcs12Reader reader = new ApplePkcs12Reader(rawData);

                try
                {
                    reader.Decrypt(password);
                    return(new ApplePkcs12CertLoader(reader, password));
                }
                catch
                {
                    reader.Dispose();
                    throw;
                }
            }

            SafeCFArrayHandle certs = Interop.AppleCrypto.X509ImportCollection(
                rawData,
                contentType,
                password);

            using (certs)
            {
                long longCount = Interop.CoreFoundation.CFArrayGetCount(certs);

                if (longCount > int.MaxValue)
                {
                    throw new CryptographicException();
                }

                int count = (int)longCount;

                // Apple returns things in the opposite order from Windows, so read backwards.
                certificateList = new List <ICertificatePal>(count);
                for (int i = count - 1; i >= 0; i--)
                {
                    IntPtr handle = Interop.CoreFoundation.CFArrayGetValueAtIndex(certs, i);

                    if (handle != IntPtr.Zero)
                    {
                        ICertificatePal?certPal = CertificatePal.FromHandle(handle, throwOnFail: false);

                        if (certPal != null)
                        {
                            certificateList.Add(certPal);
                        }
                    }
                }
            }

            return(new CertCollectionLoader(certificateList));
        }
Exemplo n.º 26
0
            protected override byte[] GetSubjectPublicKeyInfo(X509Certificate2 cert)
            {
                AppleCertificatePal pal = (AppleCertificatePal)cert.Pal;

                return(pal.SubjectPublicKeyInfo);
            }
Exemplo n.º 27
0
            public AsymmetricAlgorithm DecodePublicKey(Oid oid, byte[] encodedKeyValue, byte[] encodedParameters,
                                                       ICertificatePal certificatePal)
            {
                const int           errSecInvalidKeyRef      = -67712;
                const int           errSecUnsupportedKeySize = -67735;
                AppleCertificatePal applePal = certificatePal as AppleCertificatePal;

                if (applePal != null)
                {
                    SafeSecKeyRefHandle key = Interop.AppleCrypto.X509GetPublicKey(applePal.CertificateHandle);

                    switch (oid.Value)
                    {
                    case Oids.Rsa:
                        Debug.Assert(!key.IsInvalid);
                        return(new RSAImplementation.RSASecurityTransforms(key));

                    case Oids.Dsa:
                        if (key.IsInvalid)
                        {
                            // SecCertificateCopyKey returns null for DSA, so fall back to manually building it.
                            return(DecodeDsaPublicKey(encodedKeyValue, encodedParameters));
                        }
                        return(new DSAImplementation.DSASecurityTransforms(key));

                    case Oids.EcPublicKey:
                        // If X509GetPublicKey uses the new SecCertificateCopyKey API it can return an invalid
                        // key reference for unsupported algorithms. This currently happens for the BrainpoolP160r1
                        // algorithm in the test suite (as of macOS Mojave Developer Preview 4).
                        if (key.IsInvalid)
                        {
                            throw Interop.AppleCrypto.CreateExceptionForOSStatus(errSecInvalidKeyRef);
                        }
                        // EccGetKeySizeInBits can fail for two reasons. First, the Apple implementation has changed
                        // and we receive values from API that were not previously handled. In that case the CoreFX
                        // implementation will need to be adjusted to handle these values. Second, we deliberately
                        // return 0 from the native code to prevent hitting buggy API implementations in Apple code
                        // later.
                        if (Interop.AppleCrypto.EccGetKeySizeInBits(key) == 0)
                        {
                            key.Dispose();
                            throw Interop.AppleCrypto.CreateExceptionForOSStatus(errSecUnsupportedKeySize);
                        }
                        return(new ECDsaImplementation.ECDsaSecurityTransforms(key));
                    }

                    key.Dispose();
                }
                else
                {
                    switch (oid.Value)
                    {
                    case Oids.Rsa:
                        return(DecodeRsaPublicKey(encodedKeyValue));

                    case Oids.Dsa:
                        return(DecodeDsaPublicKey(encodedKeyValue, encodedParameters));
                    }
                }

                throw new NotSupportedException(SR.NotSupported_KeyAlgorithm);
            }