2009-12-02 Jb Evain <jbevain@novell.com>
[mcs.git] / class / corlib / Mono.Security / StrongNameManager.cs
blob4567c8b35b679b60e4d9d996f8a06d655adc5289
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 //
11 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
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.
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;
42 using Mono.Security.Cryptography;
43 using Mono.Xml;
45 namespace Mono.Security {
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
80 internal class StrongNameManager {
82 private class Element {
83 internal Hashtable assemblies;
85 public Element ()
87 assemblies = new Hashtable ();
90 public Element (string assembly, string users) : this ()
92 assemblies.Add (assembly, users);
95 public string GetUsers (string assembly)
97 return (string) assemblies [assembly];
101 static private Hashtable mappings;
102 static private Hashtable tokens;
104 static StrongNameManager ()
108 // note: more than one configuration file can be loaded at the
109 // same time (e.g. user specific and machine specific config).
110 static public void LoadConfig (string filename)
112 if (File.Exists (filename)) {
113 SecurityParser sp = new SecurityParser ();
114 using (StreamReader sr = new StreamReader (filename)) {
115 string xml = sr.ReadToEnd ();
116 sp.LoadXml (xml);
118 SecurityElement root = sp.ToXml ();
119 if ((root != null) && (root.Tag == "configuration")) {
120 SecurityElement strongnames = root.SearchForChildByTag ("strongNames");
121 if ((strongnames != null) && (strongnames.Children.Count > 0)) {
122 SecurityElement mapping = strongnames.SearchForChildByTag ("pubTokenMapping");
123 if ((mapping != null) && (mapping.Children.Count > 0)) {
124 LoadMapping (mapping);
127 SecurityElement settings = strongnames.SearchForChildByTag ("verificationSettings");
128 if ((settings != null) && (settings.Children.Count > 0)) {
129 LoadVerificationSettings (settings);
136 static private void LoadMapping (SecurityElement mapping)
138 if (mappings == null) {
139 mappings = new Hashtable ();
142 lock (mappings.SyncRoot) {
143 foreach (SecurityElement item in mapping.Children) {
144 if (item.Tag != "map")
145 continue;
147 string token = item.Attribute ("Token");
148 if ((token == null) || (token.Length != 16))
149 continue; // invalid entry
150 token = token.ToUpper (CultureInfo.InvariantCulture);
152 string publicKey = item.Attribute ("PublicKey");
153 if (publicKey == null)
154 continue; // invalid entry
156 // watch for duplicate entries
157 if (mappings [token] == null) {
158 mappings.Add (token, publicKey);
160 else {
161 // replace existing mapping
162 mappings [token] = publicKey;
168 static private void LoadVerificationSettings (SecurityElement settings)
170 if (tokens == null) {
171 tokens = new Hashtable ();
174 lock (tokens.SyncRoot) {
175 foreach (SecurityElement item in settings.Children) {
176 if (item.Tag != "skip")
177 continue;
179 string token = item.Attribute ("Token");
180 if (token == null)
181 continue; // bad entry
182 token = token.ToUpper (CultureInfo.InvariantCulture);
184 string assembly = item.Attribute ("Assembly");
185 if (assembly == null)
186 assembly = "*";
188 string users = item.Attribute ("Users");
189 if (users == null)
190 users = "*";
192 Element el = (Element) tokens [token];
193 if (el == null) {
194 // new token
195 el = new Element (assembly, users);
196 tokens.Add (token, el);
197 continue;
200 // existing token
201 string a = (string) el.assemblies [assembly];
202 if (a == null) {
203 // new assembly
204 el.assemblies.Add (assembly, users);
205 continue;
208 // existing assembly
209 if (users == "*") {
210 // all users (drop current users)
211 el.assemblies [assembly] = "*";
212 continue;
215 // new users, add to existing
216 string existing = (string) el.assemblies [assembly];
217 string newusers = String.Concat (existing, ",", users);
218 el.assemblies [assembly] = newusers;
223 static public byte[] GetMappedPublicKey (byte[] token)
225 if ((mappings == null) || (token == null))
226 return null;
228 string t = CryptoConvert.ToHex (token);
229 string pk = (string) mappings [t];
230 if (pk == null)
231 return null;
233 return CryptoConvert.FromHex (pk);
236 // it is possible to skip verification for assemblies
237 // or a strongname public key using the "sn" tool.
238 // note: only the runtime checks if the assembly is loaded
239 // from the GAC to skip verification
240 static public bool MustVerify (AssemblyName an)
242 if ((an == null) || (tokens == null))
243 return true;
245 string token = CryptoConvert.ToHex (an.GetPublicKeyToken ());
246 Element el = (Element) tokens [token];
247 if (el != null) {
248 // look for this specific assembly first
249 string users = el.GetUsers (an.Name);
250 if (users == null) {
251 // nothing for the specific assembly
252 // so look for "*" assembly
253 users = el.GetUsers ("*");
256 if (users != null) {
257 // applicable to any user ?
258 if (users == "*")
259 return false;
260 // applicable to the current user ?
261 return (users.IndexOf (Environment.UserName) < 0);
265 // we must check verify the strongname on the assembly
266 return true;
269 public override string ToString ()
271 StringBuilder sb = new StringBuilder ();
272 sb.Append ("Public Key Token\tAssemblies\t\tUsers");
273 sb.Append (Environment.NewLine);
274 foreach (DictionaryEntry token in tokens) {
275 sb.Append ((string)token.Key);
276 Element t = (Element) token.Value;
277 bool first = true;
278 foreach (DictionaryEntry assembly in t.assemblies) {
279 if (first) {
280 sb.Append ("\t");
281 first = false;
283 else {
284 sb.Append ("\t\t\t");
286 sb.Append ((string)assembly.Key);
287 sb.Append ("\t");
288 string users = (string)assembly.Value;
289 if (users == "*")
290 users = "All users";
291 sb.Append (users);
292 sb.Append (Environment.NewLine);
295 return sb.ToString ();