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; } }
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."); }
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); }
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(); } }
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)); }
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 }