2 // StrongNameManager.cs - StrongName Management
5 // Sebastien Pouliot <sebastien@ximian.com>
7 // (C) 2004 Novell (http://www.novell.com)
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:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
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.
34 using System.Collections;
35 using System.Globalization;
37 using System.Reflection;
38 using System.Security;
39 using System.Security.Cryptography;
42 using Mono.Security.Cryptography;
45 namespace Mono.Security {
49 * in_gac ---------------------------------\
57 * bool StrongNameManager.MustVerify
61 * Token --------------------------\
66 * Assembly Name --------------------------|
71 * User ---------------------------|
76 * return false return true
77 * SKIP VERIFICATION VERIFY ASSEMBLY
80 internal class StrongNameManager {
82 private class Element {
83 internal Hashtable assemblies;
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 ();
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")
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);
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")
179 string token = item.Attribute ("Token");
181 continue; // bad entry
182 token = token.ToUpper (CultureInfo.InvariantCulture);
184 string assembly = item.Attribute ("Assembly");
185 if (assembly == null)
188 string users = item.Attribute ("Users");
192 Element el = (Element) tokens [token];
195 el = new Element (assembly, users);
196 tokens.Add (token, el);
201 string a = (string) el.assemblies [assembly];
204 el.assemblies.Add (assembly, users);
210 // all users (drop current users)
211 el.assemblies [assembly] = "*";
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))
228 string t = CryptoConvert.ToHex (token);
229 string pk = (string) mappings [t];
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))
245 string token = CryptoConvert.ToHex (an.GetPublicKeyToken ());
246 Element el = (Element) tokens [token];
248 // look for this specific assembly first
249 string users = el.GetUsers (an.Name);
251 // nothing for the specific assembly
252 // so look for "*" assembly
253 users = el.GetUsers ("*");
257 // applicable to any user ?
260 // applicable to the current user ?
261 return (users.IndexOf (Environment.UserName) < 0);
265 // we must check verify the strongname on the assembly
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;
278 foreach (DictionaryEntry assembly in t.assemblies) {
284 sb.Append ("\t\t\t");
286 sb.Append ((string)assembly.Key);
288 string users = (string)assembly.Value;
292 sb.Append (Environment.NewLine);
295 return sb.ToString ();