[btls]: Cleanup certificate store initialization (#4683)
[mono.git] / mcs / class / System / Mono.Btls / MonoBtlsX509Store.cs
1 //
2 // MonoBtlsX509Store.cs
3 //
4 // Author:
5 //       Martin Baulig <martin.baulig@xamarin.com>
6 //
7 // Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining a copy
10 // of this software and associated documentation files (the "Software"), to deal
11 // in the Software without restriction, including without limitation the rights
12 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 // copies of the Software, and to permit persons to whom the Software is
14 // furnished to do so, subject to the following conditions:
15 //
16 // The above copyright notice and this permission notice shall be included in
17 // all copies or substantial portions of the Software.
18 //
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 // THE SOFTWARE.
26 #if SECURITY_DEP && MONO_FEATURE_BTLS
27 #if MONO_SECURITY_ALIAS
28 extern alias MonoSecurity;
29 #endif
30 using System;
31 using System.IO;
32 using System.Collections.Generic;
33 using System.Runtime.InteropServices;
34 using System.Runtime.CompilerServices;
35 using System.Security.Cryptography.X509Certificates;
36
37 #if MONO_SECURITY_ALIAS
38 using MonoSecurity::Mono.Security.Interface;
39 #else
40 using Mono.Security.Interface;
41 #endif
42
43 namespace Mono.Btls
44 {
45         class MonoBtlsX509Store : MonoBtlsObject
46         {
47                 internal class BoringX509StoreHandle : MonoBtlsHandle
48                 {
49                         public BoringX509StoreHandle (IntPtr handle)
50                                 : base (handle, true)
51                         {
52                         }
53
54                         protected override bool ReleaseHandle ()
55                         {
56                                 mono_btls_x509_store_free (handle);
57                                 return true;
58                         }
59                 }
60
61                 new internal BoringX509StoreHandle Handle {
62                         get { return (BoringX509StoreHandle)base.Handle; }
63                 }
64
65                 [DllImport (BTLS_DYLIB)]
66                 extern static IntPtr mono_btls_x509_store_new ();
67
68                 [DllImport (BTLS_DYLIB)]
69                 extern static IntPtr mono_btls_x509_store_from_ctx (IntPtr ctx);
70
71                 [DllImport (BTLS_DYLIB)]
72                 extern static IntPtr mono_btls_x509_store_from_ssl_ctx (IntPtr handle);
73
74                 [DllImport (BTLS_DYLIB)]
75                 extern static int mono_btls_x509_store_load_locations (IntPtr handle, IntPtr file, IntPtr path);
76
77                 [DllImport (BTLS_DYLIB)]
78                 extern static int mono_btls_x509_store_set_default_paths (IntPtr handle);
79
80                 [DllImport (BTLS_DYLIB)]
81                 extern static int mono_btls_x509_store_add_cert (IntPtr handle, IntPtr x509);
82
83                 [DllImport (BTLS_DYLIB)]
84                 extern static int mono_btls_x509_store_get_count (IntPtr handle);
85
86                 [DllImport (BTLS_DYLIB)]
87                 extern static void mono_btls_x509_store_free (IntPtr handle);
88
89                 Dictionary<IntPtr,MonoBtlsX509Lookup> lookupHash;
90
91                 public void LoadLocations (string file, string path)
92                 {
93                         IntPtr filePtr = IntPtr.Zero;
94                         IntPtr pathPtr = IntPtr.Zero;
95                         try {
96                                 if (file != null)
97                                         filePtr = Marshal.StringToHGlobalAnsi (file);
98                                 if (path != null)
99                                         pathPtr = Marshal.StringToHGlobalAnsi (path);
100                                 var ret = mono_btls_x509_store_load_locations (
101                                         Handle.DangerousGetHandle (), filePtr, pathPtr);
102                                 CheckError (ret);
103                         } finally {
104                                 if (filePtr != IntPtr.Zero)
105                                         Marshal.FreeHGlobal (filePtr);
106                                 if (pathPtr != IntPtr.Zero)
107                                         Marshal.FreeHGlobal (pathPtr);
108                         }
109                 }
110
111                 public void SetDefaultPaths ()
112                 {
113                         var ret = mono_btls_x509_store_set_default_paths (Handle.DangerousGetHandle ());
114                         CheckError (ret);
115                 }
116
117                 static BoringX509StoreHandle Create_internal ()
118                 {
119                         var handle = mono_btls_x509_store_new ();
120                         if (handle == IntPtr.Zero)
121                                 throw new MonoBtlsException ();
122                         return new BoringX509StoreHandle (handle);
123                 }
124
125                 static BoringX509StoreHandle Create_internal (IntPtr store_ctx)
126                 {
127                         var handle = mono_btls_x509_store_from_ssl_ctx (store_ctx);
128                         if (handle == IntPtr.Zero)
129                                 throw new MonoBtlsException ();
130                         return new BoringX509StoreHandle (handle);
131                 }
132
133                 static BoringX509StoreHandle Create_internal (MonoBtlsSslCtx.BoringSslCtxHandle ctx)
134                 {
135                         var handle = mono_btls_x509_store_from_ssl_ctx (ctx.DangerousGetHandle ());
136                         if (handle == IntPtr.Zero)
137                                 throw new MonoBtlsException ();
138                         return new BoringX509StoreHandle (handle);
139                 }
140
141                 internal MonoBtlsX509Store ()
142                         : base (Create_internal ())
143                 {
144                 }
145
146                 internal MonoBtlsX509Store (IntPtr store_ctx)
147                         : base (Create_internal (store_ctx))
148                 {
149                 }
150
151                 internal MonoBtlsX509Store (MonoBtlsSslCtx.BoringSslCtxHandle ctx)
152                         : base (Create_internal (ctx))
153                 {
154                 }
155
156                 public void AddCertificate (MonoBtlsX509 x509)
157                 {
158                         var ret = mono_btls_x509_store_add_cert (
159                                 Handle.DangerousGetHandle (),
160                                 x509.Handle.DangerousGetHandle ());
161                         CheckError (ret);
162                 }
163
164                 public int GetCount ()
165                 {
166                         return mono_btls_x509_store_get_count (Handle.DangerousGetHandle ());
167                 }
168
169                 internal void AddTrustedRoots ()
170                 {
171                         MonoBtlsProvider.SetupCertificateStore (this, MonoTlsSettings.DefaultSettings, false);
172                 }
173
174                 public MonoBtlsX509Lookup AddLookup (MonoBtlsX509LookupType type)
175                 {
176                         if (lookupHash == null)
177                                 lookupHash = new Dictionary<IntPtr,MonoBtlsX509Lookup> ();
178
179                         /*
180                          * X509_STORE_add_lookup() returns the same 'X509_LOOKUP *' for each
181                          * unique 'X509_LOOKUP_METHOD *' (which is supposed to be a static struct)
182                          * and we want to use the same managed object for each unique 'X509_LOOKUP *'.
183                         */
184                         var lookup = new MonoBtlsX509Lookup (this, type);
185                         var nativeLookup = lookup.GetNativeLookup ();
186                         if (lookupHash.ContainsKey (nativeLookup)) {
187                                 lookup.Dispose ();
188                                 lookup = lookupHash [nativeLookup];
189                         } else {
190                                 lookupHash.Add (nativeLookup, lookup);
191                         }
192
193                         return lookup;
194                 }
195
196                 public void AddDirectoryLookup (string dir, MonoBtlsX509FileType type)
197                 {
198                         var lookup = AddLookup (MonoBtlsX509LookupType.HASH_DIR);
199                         lookup.AddDirectory (dir, type);
200                 }
201
202                 public void AddFileLookup (string file, MonoBtlsX509FileType type)
203                 {
204                         var lookup = AddLookup (MonoBtlsX509LookupType.FILE);
205                         lookup.LoadFile (file, type);
206                 }
207
208                 public void AddCollection (X509CertificateCollection collection, MonoBtlsX509TrustKind trust)
209                 {
210                         var monoLookup = new MonoBtlsX509LookupMonoCollection (collection, trust);
211                         var lookup = new MonoBtlsX509Lookup (this, MonoBtlsX509LookupType.MONO);
212                         lookup.AddMono (monoLookup);
213                 }
214
215 #if MONODROID
216                 public void AddAndroidLookup ()
217                 {
218                         var androidLookup = new MonoBtlsX509LookupAndroid ();
219                         var lookup = new MonoBtlsX509Lookup (this, MonoBtlsX509LookupType.MONO);
220                         lookup.AddMono (androidLookup);
221                 }
222 #endif
223
224                 protected override void Close ()
225                 {
226                         try {
227                                 if (lookupHash != null) {
228                                         foreach (var lookup in lookupHash.Values)
229                                                 lookup.Dispose ();
230                                         lookupHash = null;
231                                 }
232                         } finally {
233                                 base.Close ();
234                         }
235                 }
236         }
237 }
238 #endif