Merge pull request #4503 from BrzVlad/fix-appdomain-unload
[mono.git] / mcs / class / System / Mono.AppleTls / AppleCertificateHelper.cs
1 #if SECURITY_DEP && MONO_FEATURE_APPLETLS
2 //
3 // AppleCertificateHelper.cs
4 //
5 // Author:
6 //       Martin Baulig <martin.baulig@xamarin.com>
7 //
8 // Copyright (c) 2015 Xamarin, Inc.
9 //
10
11 #if MONO_SECURITY_ALIAS
12 extern alias MonoSecurity;
13 #endif
14
15 using System;
16 using System.Collections;
17 using System.Reflection;
18 using System.Runtime.InteropServices;
19 using System.Security.Cryptography.X509Certificates;
20
21 #if MONO_SECURITY_ALIAS
22 using MonoSecurity::Mono.Security.Interface;
23 #else
24 using Mono.Security.Interface;
25 #endif
26
27 namespace Mono.AppleTls
28 {
29         static class AppleCertificateHelper
30         {
31                 public static SecIdentity GetIdentity (X509Certificate certificate)
32                 {
33                         /*
34                          * If we got an 'X509Certificate2', then we require it to have a private key
35                          * and import it.
36                          */
37                         var certificate2 = certificate as X509Certificate2;
38                         if (certificate2 != null)
39                                 return SecIdentity.Import (certificate2);
40
41                         /*
42                          * Otherwise, we require the private key to be in the keychain.
43                          */
44                         using (var secCert = new SecCertificate (certificate)) {
45                                 return SecKeyChain.FindIdentity (secCert, true);
46                         }
47                 }
48
49                 public static SecIdentity GetIdentity (X509Certificate certificate, out SecCertificate[] intermediateCerts)
50                 {
51                         var identity = GetIdentity (certificate);
52
53                         var impl2 = certificate.Impl as X509Certificate2Impl;
54                         if (impl2 == null || impl2.IntermediateCertificates == null) {
55                                 intermediateCerts = new SecCertificate [0];
56                                 return identity;
57                         }
58
59                         try {
60                                 intermediateCerts = new SecCertificate [impl2.IntermediateCertificates.Count];
61                                 for (int i = 0; i < intermediateCerts.Length; i++)
62                                         intermediateCerts [i] = new SecCertificate (impl2.IntermediateCertificates [i]);
63
64                                 return identity;
65                         } catch {
66                                 identity.Dispose ();
67                                 throw;
68                         }
69                 }
70
71                 public static bool InvokeSystemCertificateValidator (
72                         ICertificateValidator2 validator, string targetHost, bool serverMode,
73                         X509CertificateCollection certificates,
74                         ref MonoSslPolicyErrors errors, ref int status11)
75                 {
76                         if (certificates == null) {
77                                 errors |= MonoSslPolicyErrors.RemoteCertificateNotAvailable;
78                                 return false;
79                         }
80
81                         if (!string.IsNullOrEmpty (targetHost)) {
82                                 var pos = targetHost.IndexOf (':');
83                                 if (pos > 0)
84                                         targetHost = targetHost.Substring (0, pos);
85                         }
86
87                         var policy = SecPolicy.CreateSslPolicy (!serverMode, targetHost);
88                         var trust = new SecTrust (certificates, policy);
89
90                         if (validator.Settings.TrustAnchors != null) {
91                                 var status = trust.SetAnchorCertificates (validator.Settings.TrustAnchors);
92                                 if (status != SecStatusCode.Success)
93                                         throw new InvalidOperationException (status.ToString ());
94                                 trust.SetAnchorCertificatesOnly (false);
95                         }
96
97                         var result = trust.Evaluate ();
98                         if (result == SecTrustResult.Unspecified)
99                                 return true;
100
101                         errors |= MonoSslPolicyErrors.RemoteCertificateChainErrors;
102                         return false;
103                 }
104         }
105 }
106 #endif