X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FSystem%2FMono.AppleTls%2FAppleCertificateHelper.cs;h=073f16080044f4d5315b339ea99418573e80d51c;hb=74a87af7f580c59f524f79508e4ad32ccff0870a;hp=d26abe989b415a863bc606a041fb63976513df85;hpb=a3304910e9e08ec965fb06ef6fa4a19257dddf8c;p=mono.git diff --git a/mcs/class/System/Mono.AppleTls/AppleCertificateHelper.cs b/mcs/class/System/Mono.AppleTls/AppleCertificateHelper.cs index d26abe989b4..073f1608004 100644 --- a/mcs/class/System/Mono.AppleTls/AppleCertificateHelper.cs +++ b/mcs/class/System/Mono.AppleTls/AppleCertificateHelper.cs @@ -36,14 +36,63 @@ namespace Mono.AppleTls */ var certificate2 = certificate as X509Certificate2; if (certificate2 != null) +#if MONOTOUCH return SecIdentity.Import (certificate2); +#else + return SecImportExport.ItemImport (certificate2); +#endif /* - * Otherwise, we require the private key to be in the keychain. + * 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 = new SecCertificate (certificate)) { return SecKeyChain.FindIdentity (secCert, true); } +#else + return null; +#endif } public static SecIdentity GetIdentity (X509Certificate certificate, out SecCertificate[] intermediateCerts) @@ -84,22 +133,28 @@ namespace Mono.AppleTls targetHost = targetHost.Substring (0, pos); } - var policy = SecPolicy.CreateSslPolicy (!serverMode, targetHost); - var trust = new SecTrust (certificates, policy); + using (var policy = SecPolicy.CreateSslPolicy (!serverMode, targetHost)) + using (var trust = new SecTrust (certificates, policy)) { + if (validator.Settings.TrustAnchors != null) { + var status = trust.SetAnchorCertificates (validator.Settings.TrustAnchors); + if (status != SecStatusCode.Success) + throw new InvalidOperationException (status.ToString ()); + trust.SetAnchorCertificatesOnly (false); + } - if (validator.Settings.TrustAnchors != null) { - var status = trust.SetAnchorCertificates (validator.Settings.TrustAnchors); - if (status != SecStatusCode.Success) - throw new InvalidOperationException (status.ToString ()); - trust.SetAnchorCertificatesOnly (false); - } + if (validator.Settings.CertificateValidationTime != null) { + var status = trust.SetVerifyDate (validator.Settings.CertificateValidationTime.Value); + if (status != SecStatusCode.Success) + throw new InvalidOperationException (status.ToString ()); + } - var result = trust.Evaluate (); - if (result == SecTrustResult.Unspecified) - return true; + var result = trust.Evaluate (); + if (result == SecTrustResult.Unspecified || result == SecTrustResult.Proceed) + return true; - errors |= MonoSslPolicyErrors.RemoteCertificateChainErrors; - return false; + errors |= MonoSslPolicyErrors.RemoteCertificateChainErrors; + return false; + } } } }