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 // 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)
108 if (File.Exists (filename)) {
109 SecurityParser sp = new SecurityParser ();
110 using (StreamReader sr = new StreamReader (filename)) {
111 string xml = sr.ReadToEnd ();
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);
123 SecurityElement settings = strongnames.SearchForChildByTag ("verificationSettings");
124 if ((settings != null) && (settings.Children.Count > 0)) {
125 LoadVerificationSettings (settings);
132 static private void LoadMapping (SecurityElement mapping)
134 if (mappings == null) {
135 mappings = new Hashtable ();
138 lock (mappings.SyncRoot) {
139 foreach (SecurityElement item in mapping.Children) {
140 if (item.Tag != "map")
143 string token = item.Attribute ("Token");
144 if ((token == null) || (token.Length != 16))
145 continue; // invalid entry
146 token = token.ToUpper (CultureInfo.InvariantCulture);
148 string publicKey = item.Attribute ("PublicKey");
149 if (publicKey == null)
150 continue; // invalid entry
152 // watch for duplicate entries
153 if (mappings [token] == null) {
154 mappings.Add (token, publicKey);
157 // replace existing mapping
158 mappings [token] = publicKey;
164 static private void LoadVerificationSettings (SecurityElement settings)
166 if (tokens == null) {
167 tokens = new Hashtable ();
170 lock (tokens.SyncRoot) {
171 foreach (SecurityElement item in settings.Children) {
172 if (item.Tag != "skip")
175 string token = item.Attribute ("Token");
177 continue; // bad entry
178 token = token.ToUpper (CultureInfo.InvariantCulture);
180 string assembly = item.Attribute ("Assembly");
181 if (assembly == null)
184 string users = item.Attribute ("Users");
188 Element el = (Element) tokens [token];
191 el = new Element (assembly, users);
192 tokens.Add (token, el);
197 string a = (string) el.assemblies [assembly];
200 el.assemblies.Add (assembly, users);
206 // all users (drop current users)
207 el.assemblies [assembly] = "*";
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;
219 static public byte[] GetMappedPublicKey (byte[] token)
221 if ((mappings == null) || (token == null))
224 string t = CryptoConvert.ToHex (token);
225 string pk = (string) mappings [t];
229 return CryptoConvert.FromHex (pk);
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)
238 if ((an == null) || (tokens == null))
241 string token = CryptoConvert.ToHex (an.GetPublicKeyToken ());
242 Element el = (Element) tokens [token];
244 // look for this specific assembly first
245 string users = el.GetUsers (an.Name);
247 // nothing for the specific assembly
248 // so look for "*" assembly
249 users = el.GetUsers ("*");
253 // applicable to any user ?
256 // applicable to the current user ?
257 return (users.IndexOf (Environment.UserName) < 0);
261 // we must check verify the strongname on the assembly
265 public override string ToString ()
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;
274 foreach (DictionaryEntry assembly in t.assemblies) {
280 sb.Append ("\t\t\t");
282 sb.Append ((string)assembly.Key);
284 string users = (string)assembly.Value;
288 sb.Append (Environment.NewLine);
291 return sb.ToString ();