Beispiel #1
0
        public static SafeSecIdentityHandle GetIdentity(X509Certificate certificate, out SafeSecCertificateHandle[] intermediateCerts)
        {
            var identity = GetIdentity(certificate);

            var impl2 = certificate.Impl as X509Certificate2Impl;

            if (impl2 == null || impl2.IntermediateCertificates == null)
            {
                intermediateCerts = new SafeSecCertificateHandle [0];
                return(identity);
            }

            intermediateCerts = new SafeSecCertificateHandle [impl2.IntermediateCertificates.Count];

            try {
                for (int i = 0; i < intermediateCerts.Length; i++)
                {
                    intermediateCerts [i] = MonoCertificatePal.FromOtherCertificate(impl2.IntermediateCertificates[i]);
                }

                return(identity);
            } catch {
                for (int i = 0; i < intermediateCerts.Length; i++)
                {
                    intermediateCerts [i]?.Dispose();
                }
                identity?.Dispose();
                throw;
            }
        }
Beispiel #2
0
        static SafeSecKeyRefHandle ImportPrivateKey(X509Certificate2 certificate)
        {
            if (!certificate.HasPrivateKey)
            {
                throw new NotSupportedException();
            }

            CFArray items;

            using (var data = CFData.FromData(ExportKey((RSA)certificate.PrivateKey)))
                items = ItemImport(data, SecExternalFormat.OpenSSL, SecExternalItemType.PrivateKey);

            try {
                if (items.Count != 1)
                {
                    throw new InvalidOperationException("Private key import failed.");
                }

                var imported = items[0];
                if (!MonoCertificatePal.IsSecKey(imported))
                {
                    throw new InvalidOperationException("Private key import doesn't return SecKey.");
                }

                return(new SafeSecKeyRefHandle(imported, items.Handle));
            } finally {
                items.Dispose();
            }
        }
        public static SafeSecIdentityHandle FindIdentity(SafeSecCertificateHandle certificate, bool throwOnError = false)
        {
            if (certificate == null || certificate.IsInvalid)
            {
                throw new ObjectDisposedException(nameof(certificate));
            }
            var identity = FindIdentity(cert => MonoCertificatePal.Equals(certificate, cert)) ?? new SafeSecIdentityHandle();

            if (!throwOnError || identity.IsInvalid)
            {
                return(identity);
            }

            var subject = MonoCertificatePal.GetSubjectSummary(certificate);

            throw new InvalidOperationException($"Could not find SecIdentity for certificate '{subject}' in keychain.");
        }
Beispiel #4
0
        static public SafeSecIdentityHandle ItemImport(X509Certificate2 certificate)
        {
            if (!certificate.HasPrivateKey)
            {
                throw new NotSupportedException();
            }

            using (var key = ImportPrivateKey(certificate))
                using (var cert = MonoCertificatePal.FromOtherCertificate(certificate)) {
                    var identity = SecIdentityCreate(IntPtr.Zero, cert.DangerousGetHandle(), key.DangerousGetHandle());
                    if (!MonoCertificatePal.IsSecIdentity(identity))
                    {
                        throw new InvalidOperationException();
                    }

                    return(new SafeSecIdentityHandle(identity, true));
                }
        }
        static SafeSecIdentityHandle FindIdentity(Predicate <SafeSecCertificateHandle> filter)
        {
            Initialize();

            /*
             * Unfortunately, SecItemCopyMatching() does not allow any search
             * filters when looking up an identity.
             *
             * The following lookup will return all identities from the keychain -
             * we then need need to find the right one.
             */
            using (var query = CFMutableDictionary.Create()) {
                query.SetValue(SecClassKey, SecClassIdentity);
                query.SetValue(CFBoolean.True.Handle, ReturnRef);
                query.SetValue(MatchLimitAll, MatchLimit);

                var status = SecItemCopyMatching(query.Handle, out var ptr);
                if (status != SecStatusCode.Success || ptr == IntPtr.Zero)
                {
                    return(null);
                }

                using (var array = new CFArray(ptr, false)) {
                    for (int i = 0; i < array.Count; i++)
                    {
                        var item = array[i];
                        if (!MonoCertificatePal.IsSecIdentity(item))
                        {
                            throw new InvalidOperationException();
                        }
                        using (var identity = new SafeSecIdentityHandle(item))
                            using (var certificate = MonoCertificatePal.GetCertificate(identity)) {
                                if (filter(certificate))
                                {
                                    return(new SafeSecIdentityHandle(item));
                                }
                            }
                    }
                }
            }

            return(null);
        }
Beispiel #6
0
        public SecTrust(X509CertificateCollection certificates, SecPolicy policy)
        {
            if (certificates == null)
            {
                throw new ArgumentNullException("certificates");
            }

            var array = new SafeSecCertificateHandle [certificates.Count];
            int i     = 0;

            foreach (var certificate in certificates)
            {
                array [i++] = MonoCertificatePal.FromOtherCertificate(certificate);
            }
            Initialize(array, policy);
            for (i = 0; i < array.Length; i++)
            {
                array [i].Dispose();
            }
        }
Beispiel #7
0
        public SecStatusCode SetAnchorCertificates(X509CertificateCollection certificates)
        {
            if (handle == IntPtr.Zero)
            {
                throw new ObjectDisposedException("SecTrust");
            }
            if (certificates == null)
            {
                return(SecTrustSetAnchorCertificates(handle, IntPtr.Zero));
            }

            var array = new SafeSecCertificateHandle [certificates.Count];
            int i     = 0;

            foreach (var certificate in certificates)
            {
                array [i++] = MonoCertificatePal.FromOtherCertificate(certificate);
            }
            return(SetAnchorCertificates(array));
        }
Beispiel #8
0
        public static SafeSecIdentityHandle GetIdentity(X509Certificate certificate)
        {
            /*
             * If we got an 'X509Certificate2', then we require it to have a private key
             * and import it.
             */
            var certificate2 = certificate as X509Certificate2;

            if (certificate2 != null)
            {
                return(MonoCertificatePal.ImportIdentity(certificate2));
            }

            /*
             * Reading Certificates from the Mac Keychain
             * ==========================================
             *
             * Reading the private key from the keychain is a new feature introduced with
             * AppleTls on XamMac and iOS. On Desktop Mono, this new feature has several
             * known issues and it also did not received any testing yet. We go back to the old
             * way of doing things, which is to explicitly provide an X509Certificate2 with a
             * private key.
             *
             * Keychain Dialog Popups
             * ======================
             *
             * When using Xamarin.Mac or Xamarin.iOS, we try to search the keychain
             * for the certificate and private key.
             *
             * On Xamarin.iOS, this is easy because each app has its own keychain.
             *
             * On Xamarin.Mac, the .app package needs to be trusted via code-sign
             * to get permission to access the user's keychain. [FIXME: I still have to
             * research how to actually do that.] Without this, you will get a popup
             * message each time, asking you whether you want to allow the app to access
             * the keychain, but you can make these go away by selecting "Trust always".
             *
             * On Desktop Mono, this is problematic because selecting "Trust always"
             * give the 'mono' binary (and thus everything you'll ever run with Mono)
             * permission to retrieve the private key from the keychain.
             *
             * This code would also trigger constant keychain popup messages,
             * which could only be suppressed by granting full trust. It also makes it
             * impossible to run Mono in headless mode.
             *
             * SecIdentityCreate
             * =================
             *
             * To avoid these problems, we are currently using an undocumented API
             * called SecIdentityRef() to avoid using the Mac keychain whenever a
             * X509Certificate2 with a private key is used.
             *
             * On iOS and XamMac, you can still provide the X509Certificate without
             * a private key - in this case, a keychain search will be performed (and you
             * may get a popup message on XamMac).
             */

#if MOBILE
            using (var secCert = MonoCertificatePal.FromOtherCertificate(certificate))
                return(MonoCertificatePal.FindIdentity(secCert, true));
#else
            return(new SafeSecIdentityHandle());
#endif
        }