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 Element()62 public Element () 63 { 64 assemblies = new Hashtable (); 65 } 66 Element(string assembly, string users)67 public Element (string assembly, string users) : this () 68 { 69 assemblies.Add (assembly, users); 70 } 71 GetUsers(string assembly)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 StrongNameManager()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). LoadConfig(string filename)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 LoadMapping(SecurityElement mapping)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 LoadVerificationSettings(SecurityElement settings)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 GetMappedPublicKey(byte[] token)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 MustVerify(AssemblyName an)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 ToString()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 } 281