[gacutil] Use IKVM.Reflection instead of System.Reflection (#3582)
[mono.git] / mcs / tools / 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 using System;
11 using System.Collections;
12 using System.Globalization;
13 using System.IO;
14 using System.Reflection;
15 using System.Security;
16 using System.Security.Cryptography;
17 using System.Text;
18
19 using Mono.Security.Cryptography;
20 using Mono.Xml;
21
22 namespace Mono.Security {
23
24         /* RUNTIME
25          *                              yes
26          *      in_gac ---------------------------------\
27          *              |                               |
28          *              | no                            \/
29          *              |                       return true
30          * CLASS LIBRARY|
31          *              |
32          *              |
33          *              |                               
34          *      bool StrongNameManager.MustVerify
35          *              |
36          *              |
37          *              \/              not found       
38          *              Token --------------------------\
39          *              |                               |
40          *              | present ?                     |
41          *              |                               |
42          *              \/              not found       |
43          *      Assembly Name --------------------------|
44          *              |                               |
45          *              | present ?                     |
46          *              | or "*"                        |
47          *              \/              not found       |
48          *              User ---------------------------|
49          *              |                               |
50          *              | present ?                     |
51          *              | or "*"                        |
52          *              \/                              \/
53          *      return false                    return true
54          *      SKIP VERIFICATION               VERIFY ASSEMBLY
55          */
56
57         internal class StrongNameManager {
58
59                 private class Element {
60                         internal Hashtable assemblies;
61
62                         public Element () 
63                         {
64                                 assemblies = new Hashtable ();
65                         }
66
67                         public Element (string assembly, string users) : this ()
68                         {
69                                 assemblies.Add (assembly, users);
70                         }
71
72                         public string GetUsers (string assembly) 
73                         {
74                                 return (string) assemblies [assembly];
75                         }
76                 }
77
78                 static private Hashtable mappings;
79                 static private Hashtable tokens;
80
81                 static StrongNameManager () 
82                 {
83                 }
84
85                 // note: more than one configuration file can be loaded at the 
86                 // same time (e.g. user specific and machine specific config).
87                 static public void LoadConfig (string filename) 
88                 {
89                         if (File.Exists (filename)) {
90                                 SecurityParser sp = new SecurityParser ();
91                                 using (StreamReader sr = new StreamReader (filename)) {
92                                         string xml = sr.ReadToEnd ();
93                                         sp.LoadXml (xml);
94                                 }
95                                 SecurityElement root = sp.ToXml ();
96                                 if ((root != null) && (root.Tag == "configuration")) {
97                                         SecurityElement strongnames  = root.SearchForChildByTag ("strongNames");
98                                         if ((strongnames != null) && (strongnames.Children.Count > 0)) {
99                                                 SecurityElement mapping  = strongnames.SearchForChildByTag ("pubTokenMapping");
100                                                 if ((mapping != null) && (mapping.Children.Count > 0)) {
101                                                         LoadMapping (mapping);
102                                                 }
103
104                                                 SecurityElement settings = strongnames.SearchForChildByTag ("verificationSettings");
105                                                 if ((settings != null) && (settings.Children.Count > 0)) {
106                                                         LoadVerificationSettings (settings);
107                                                 }
108                                         }
109                                 }
110                         }
111                 }
112
113                 static private void LoadMapping (SecurityElement mapping) 
114                 {
115                         if (mappings == null) {
116                                 mappings = new Hashtable ();
117                         }
118
119                         lock (mappings.SyncRoot) {
120                                 foreach (SecurityElement item in mapping.Children) {
121                                         if (item.Tag != "map")
122                                                 continue;
123
124                                         string token = item.Attribute ("Token");
125                                         if ((token == null) || (token.Length != 16))
126                                                 continue; // invalid entry
127                                         token = token.ToUpper (CultureInfo.InvariantCulture);
128
129                                         string publicKey = item.Attribute ("PublicKey");
130                                         if (publicKey == null)
131                                                 continue; // invalid entry
132                                 
133                                         // watch for duplicate entries
134                                         if (mappings [token] == null) {
135                                                 mappings.Add (token, publicKey);
136                                         }
137                                         else {
138                                                 // replace existing mapping
139                                                 mappings [token] = publicKey;
140                                         }
141                                 }
142                         }
143                 }
144
145                 static private void LoadVerificationSettings (SecurityElement settings) 
146                 {
147                         if (tokens == null) {
148                                 tokens = new Hashtable ();
149                         }
150
151                         lock (tokens.SyncRoot) {
152                                 foreach (SecurityElement item in settings.Children) {
153                                         if (item.Tag != "skip")
154                                                 continue;
155
156                                         string token = item.Attribute ("Token");
157                                         if (token == null)
158                                                 continue;       // bad entry
159                                         token = token.ToUpper (CultureInfo.InvariantCulture);
160
161                                         string assembly = item.Attribute ("Assembly");
162                                         if (assembly == null)
163                                                 assembly = "*";
164
165                                         string users = item.Attribute ("Users");
166                                         if (users == null)
167                                                 users = "*";
168
169                                         Element el = (Element) tokens [token];
170                                         if (el == null) {
171                                                 // new token
172                                                 el = new Element (assembly, users);
173                                                 tokens.Add (token, el);
174                                                 continue;
175                                         }
176
177                                         // existing token
178                                         string a = (string) el.assemblies [assembly];
179                                         if (a == null) {
180                                                 // new assembly
181                                                 el.assemblies.Add (assembly, users);
182                                                 continue;
183                                         }
184
185                                         // existing assembly
186                                         if (users == "*") {
187                                                 // all users (drop current users)
188                                                 el.assemblies [assembly] = "*";
189                                                 continue;
190                                         }
191
192                                         // new users, add to existing
193                                         string existing = (string) el.assemblies [assembly];
194                                         string newusers = String.Concat (existing, ",", users);
195                                         el.assemblies [assembly] = newusers;
196                                 }
197                         }
198                 }
199
200                 static public byte[] GetMappedPublicKey (byte[] token) 
201                 {
202                         if ((mappings == null) || (token == null))
203                                 return null;
204
205                         string t = CryptoConvert.ToHex (token);
206                         string pk = (string) mappings [t];
207                         if (pk == null)
208                                 return null;
209
210                         return CryptoConvert.FromHex (pk);
211                 }
212
213                 // it is possible to skip verification for assemblies 
214                 // or a strongname public key using the "sn" tool.
215                 // note: only the runtime checks if the assembly is loaded 
216                 // from the GAC to skip verification
217                 static public bool MustVerify (AssemblyName an)
218                 {
219                         if ((an == null) || (tokens == null))
220                                 return true;
221
222                         string token = CryptoConvert.ToHex (an.GetPublicKeyToken ());
223                         Element el = (Element) tokens [token];
224                         if (el != null) {
225                                 // look for this specific assembly first
226                                 string users = el.GetUsers (an.Name);
227                                 if (users == null) {
228                                         // nothing for the specific assembly
229                                         // so look for "*" assembly
230                                         users = el.GetUsers ("*");
231                                 }
232
233                                 if (users != null) {
234                                         // applicable to any user ?
235                                         if (users == "*")
236                                                 return false;
237                                         // applicable to the current user ?
238                                         return (users.IndexOf (Environment.UserName) < 0);
239                                 }
240                         }
241
242                         // we must check verify the strongname on the assembly
243                         return true;
244                 }
245
246                 public override string ToString () 
247                 {
248                         StringBuilder sb = new StringBuilder ();
249                         sb.Append ("Public Key Token\tAssemblies\t\tUsers");
250                         sb.Append (Environment.NewLine);
251                         if (tokens == null) {
252                                 sb.Append ("none");
253                                 return sb.ToString ();
254                         }
255
256                         foreach (DictionaryEntry token in tokens) {
257                                 sb.Append ((string)token.Key);
258                                 Element t = (Element) token.Value;
259                                 bool first = true;
260                                 foreach (DictionaryEntry assembly in t.assemblies) {
261                                         if (first) {
262                                                 sb.Append ("\t");
263                                                 first = false;
264                                         }
265                                         else {
266                                                 sb.Append ("\t\t\t");
267                                         }
268                                         sb.Append ((string)assembly.Key);
269                                         sb.Append ("\t");
270                                         string users = (string)assembly.Value;
271                                         if (users == "*")
272                                                 users = "All users";
273                                         sb.Append (users);
274                                         sb.Append (Environment.NewLine);
275                                 }
276                         }
277                         return sb.ToString ();
278                 }
279         }
280 }