Clean up some static initializers
[mono.git] / mcs / class / corlib / Mono.Security / StrongNameManager.cs
1 //
2 // StrongNameManager.cs - StrongName Management
3 //
4 // Author:
5 //      Sebastien Pouliot  <sebastien@ximian.com>
6 //
7 // (C) 2004 Novell (http://www.novell.com)
8 //
9
10 //
11 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33 using System;
34 using System.Collections;
35 using System.Globalization;
36 using System.IO;
37 using System.Reflection;
38 using System.Security;
39 using System.Security.Cryptography;
40 using System.Text;
41
42 using Mono.Security.Cryptography;
43 using Mono.Xml;
44
45 namespace Mono.Security {
46
47         /* RUNTIME
48          *                              yes
49          *      in_gac ---------------------------------\
50          *              |                               |
51          *              | no                            \/
52          *              |                       return true
53          * CLASS LIBRARY|
54          *              |
55          *              |
56          *              |                               
57          *      bool StrongNameManager.MustVerify
58          *              |
59          *              |
60          *              \/              not found       
61          *              Token --------------------------\
62          *              |                               |
63          *              | present ?                     |
64          *              |                               |
65          *              \/              not found       |
66          *      Assembly Name --------------------------|
67          *              |                               |
68          *              | present ?                     |
69          *              | or "*"                        |
70          *              \/              not found       |
71          *              User ---------------------------|
72          *              |                               |
73          *              | present ?                     |
74          *              | or "*"                        |
75          *              \/                              \/
76          *      return false                    return true
77          *      SKIP VERIFICATION               VERIFY ASSEMBLY
78          */
79
80         internal class StrongNameManager {
81
82                 private class Element {
83                         internal Hashtable assemblies;
84
85                         public Element () 
86                         {
87                                 assemblies = new Hashtable ();
88                         }
89
90                         public Element (string assembly, string users) : this ()
91                         {
92                                 assemblies.Add (assembly, users);
93                         }
94
95                         public string GetUsers (string assembly) 
96                         {
97                                 return (string) assemblies [assembly];
98                         }
99                 }
100
101                 static private Hashtable mappings;
102                 static private Hashtable tokens;
103
104                 // note: more than one configuration file can be loaded at the 
105                 // same time (e.g. user specific and machine specific config).
106                 static public void LoadConfig (string filename) 
107                 {
108                         if (File.Exists (filename)) {
109                                 SecurityParser sp = new SecurityParser ();
110                                 using (StreamReader sr = new StreamReader (filename)) {
111                                         string xml = sr.ReadToEnd ();
112                                         sp.LoadXml (xml);
113                                 }
114                                 SecurityElement root = sp.ToXml ();
115                                 if ((root != null) && (root.Tag == "configuration")) {
116                                         SecurityElement strongnames  = root.SearchForChildByTag ("strongNames");
117                                         if ((strongnames != null) && (strongnames.Children.Count > 0)) {
118                                                 SecurityElement mapping  = strongnames.SearchForChildByTag ("pubTokenMapping");
119                                                 if ((mapping != null) && (mapping.Children.Count > 0)) {
120                                                         LoadMapping (mapping);
121                                                 }
122
123                                                 SecurityElement settings = strongnames.SearchForChildByTag ("verificationSettings");
124                                                 if ((settings != null) && (settings.Children.Count > 0)) {
125                                                         LoadVerificationSettings (settings);
126                                                 }
127                                         }
128                                 }
129                         }
130                 }
131
132                 static private void LoadMapping (SecurityElement mapping) 
133                 {
134                         if (mappings == null) {
135                                 mappings = new Hashtable ();
136                         }
137
138                         lock (mappings.SyncRoot) {
139                                 foreach (SecurityElement item in mapping.Children) {
140                                         if (item.Tag != "map")
141                                                 continue;
142
143                                         string token = item.Attribute ("Token");
144                                         if ((token == null) || (token.Length != 16))
145                                                 continue; // invalid entry
146                                         token = token.ToUpper (CultureInfo.InvariantCulture);
147
148                                         string publicKey = item.Attribute ("PublicKey");
149                                         if (publicKey == null)
150                                                 continue; // invalid entry
151                                 
152                                         // watch for duplicate entries
153                                         if (mappings [token] == null) {
154                                                 mappings.Add (token, publicKey);
155                                         }
156                                         else {
157                                                 // replace existing mapping
158                                                 mappings [token] = publicKey;
159                                         }
160                                 }
161                         }
162                 }
163
164                 static private void LoadVerificationSettings (SecurityElement settings) 
165                 {
166                         if (tokens == null) {
167                                 tokens = new Hashtable ();
168                         }
169
170                         lock (tokens.SyncRoot) {
171                                 foreach (SecurityElement item in settings.Children) {
172                                         if (item.Tag != "skip")
173                                                 continue;
174
175                                         string token = item.Attribute ("Token");
176                                         if (token == null)
177                                                 continue;       // bad entry
178                                         token = token.ToUpper (CultureInfo.InvariantCulture);
179
180                                         string assembly = item.Attribute ("Assembly");
181                                         if (assembly == null)
182                                                 assembly = "*";
183
184                                         string users = item.Attribute ("Users");
185                                         if (users == null)
186                                                 users = "*";
187
188                                         Element el = (Element) tokens [token];
189                                         if (el == null) {
190                                                 // new token
191                                                 el = new Element (assembly, users);
192                                                 tokens.Add (token, el);
193                                                 continue;
194                                         }
195
196                                         // existing token
197                                         string a = (string) el.assemblies [assembly];
198                                         if (a == null) {
199                                                 // new assembly
200                                                 el.assemblies.Add (assembly, users);
201                                                 continue;
202                                         }
203
204                                         // existing assembly
205                                         if (users == "*") {
206                                                 // all users (drop current users)
207                                                 el.assemblies [assembly] = "*";
208                                                 continue;
209                                         }
210
211                                         // new users, add to existing
212                                         string existing = (string) el.assemblies [assembly];
213                                         string newusers = String.Concat (existing, ",", users);
214                                         el.assemblies [assembly] = newusers;
215                                 }
216                         }
217                 }
218
219                 static public byte[] GetMappedPublicKey (byte[] token) 
220                 {
221                         if ((mappings == null) || (token == null))
222                                 return null;
223
224                         string t = CryptoConvert.ToHex (token);
225                         string pk = (string) mappings [t];
226                         if (pk == null)
227                                 return null;
228
229                         return CryptoConvert.FromHex (pk);
230                 }
231
232                 // it is possible to skip verification for assemblies 
233                 // or a strongname public key using the "sn" tool.
234                 // note: only the runtime checks if the assembly is loaded 
235                 // from the GAC to skip verification
236                 static public bool MustVerify (AssemblyName an)
237                 {
238                         if ((an == null) || (tokens == null))
239                                 return true;
240
241                         string token = CryptoConvert.ToHex (an.GetPublicKeyToken ());
242                         Element el = (Element) tokens [token];
243                         if (el != null) {
244                                 // look for this specific assembly first
245                                 string users = el.GetUsers (an.Name);
246                                 if (users == null) {
247                                         // nothing for the specific assembly
248                                         // so look for "*" assembly
249                                         users = el.GetUsers ("*");
250                                 }
251
252                                 if (users != null) {
253                                         // applicable to any user ?
254                                         if (users == "*")
255                                                 return false;
256                                         // applicable to the current user ?
257                                         return (users.IndexOf (Environment.UserName) < 0);
258                                 }
259                         }
260
261                         // we must check verify the strongname on the assembly
262                         return true;
263                 }
264
265                 public override string ToString () 
266                 {
267                         StringBuilder sb = new StringBuilder ();
268                         sb.Append ("Public Key Token\tAssemblies\t\tUsers");
269                         sb.Append (Environment.NewLine);
270                         foreach (DictionaryEntry token in tokens) {
271                                 sb.Append ((string)token.Key);
272                                 Element t = (Element) token.Value;
273                                 bool first = true;
274                                 foreach (DictionaryEntry assembly in t.assemblies) {
275                                         if (first) {
276                                                 sb.Append ("\t");
277                                                 first = false;
278                                         }
279                                         else {
280                                                 sb.Append ("\t\t\t");
281                                         }
282                                         sb.Append ((string)assembly.Key);
283                                         sb.Append ("\t");
284                                         string users = (string)assembly.Value;
285                                         if (users == "*")
286                                                 users = "All users";
287                                         sb.Append (users);
288                                         sb.Append (Environment.NewLine);
289                                 }
290                         }
291                         return sb.ToString ();
292                 }
293         }
294 }