Merge pull request #2080 from upsilon/fix-point-constructor
[mono.git] / mcs / class / System.Web / System.Web.Configuration_2.0 / MachineKeySection.cs
1 //
2 // System.Web.Configuration.MachineKeySection
3 //
4 // Authors:
5 //      Chris Toshok (toshok@ximian.com)
6 //      Sebastien Pouliot  <sebastien@ximian.com>
7 //
8 // (c) Copyright 2005, 2010 Novell, Inc (http://www.novell.com)
9 //
10
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32
33 using System;
34 using System.ComponentModel;
35 using System.Configuration;
36 using System.Security.Cryptography;
37 using System.Web.Util;
38
39 namespace System.Web.Configuration {
40
41         public sealed class MachineKeySection : ConfigurationSection
42         {
43                 static ConfigurationProperty decryptionProp;
44                 static ConfigurationProperty decryptionKeyProp;
45                 static ConfigurationProperty validationProp;
46                 static ConfigurationProperty validationKeyProp;
47                 static ConfigurationPropertyCollection properties;
48                 static MachineKeyValidationConverter converter = new MachineKeyValidationConverter ();
49                 MachineKeyValidation validation;
50
51                 static MachineKeySection ()
52                 {
53                         decryptionProp = new ConfigurationProperty ("decryption", typeof (string), "Auto",
54                                                                     PropertyHelper.WhiteSpaceTrimStringConverter,
55                                                                     PropertyHelper.NonEmptyStringValidator,
56                                                                     ConfigurationPropertyOptions.None);
57                         decryptionKeyProp = new ConfigurationProperty ("decryptionKey", typeof (string), "AutoGenerate,IsolateApps",
58                                                                        PropertyHelper.WhiteSpaceTrimStringConverter,
59                                                                        PropertyHelper.NonEmptyStringValidator,
60                                                                        ConfigurationPropertyOptions.None);
61                         validationProp = new ConfigurationProperty ("validation", typeof (string), "HMACSHA256",
62                                                                     PropertyHelper.WhiteSpaceTrimStringConverter,
63                                                                     PropertyHelper.NonEmptyStringValidator,
64                                                                     ConfigurationPropertyOptions.None);
65                         validationKeyProp = new ConfigurationProperty ("validationKey", typeof (string), "AutoGenerate,IsolateApps",
66                                                                        PropertyHelper.WhiteSpaceTrimStringConverter,
67                                                                        PropertyHelper.NonEmptyStringValidator,
68                                                                        ConfigurationPropertyOptions.None);
69
70                         properties = new ConfigurationPropertyCollection ();
71
72                         properties.Add (decryptionProp);
73                         properties.Add (decryptionKeyProp);
74                         properties.Add (validationProp);
75                         properties.Add (validationKeyProp);
76
77                         Config.AutoGenerate (MachineKeyRegistryStorage.KeyType.Encryption);
78                         Config.AutoGenerate (MachineKeyRegistryStorage.KeyType.Validation);
79                 }
80
81                 public MachineKeySection ()
82                 {
83                         // get DefaultValue from ValidationAlgorithm
84                         validation = (MachineKeyValidation) converter.ConvertFrom (null, null, ValidationAlgorithm);
85                 }
86
87                 [MonoTODO]
88                 public MachineKeyCompatibilityMode CompatibilityMode {
89                         get; set;
90                 }
91
92                 protected internal override void Reset (ConfigurationElement parentElement)
93                 {
94                         base.Reset (parentElement);
95                         decryption_key = null;
96                         validation_key = null;
97                         decryption_template = null;
98                         validation_template = null;
99                 }
100
101                 [TypeConverter (typeof (WhiteSpaceTrimStringConverter))]
102                 [StringValidator (MinLength = 1)]
103                 [ConfigurationProperty ("decryption", DefaultValue = "Auto")]
104                 public string Decryption {
105                         get { return (string) base [decryptionProp];}
106                         set {
107                                 decryption_template = MachineKeySectionUtils.GetDecryptionAlgorithm (value);
108                                 base[decryptionProp] = value;
109                         }
110                 }
111
112                 [TypeConverter (typeof (WhiteSpaceTrimStringConverter))]
113                 [StringValidator (MinLength = 1)]
114                 [ConfigurationProperty ("decryptionKey", DefaultValue = "AutoGenerate,IsolateApps")]
115                 public string DecryptionKey {
116                         get { return (string) base [decryptionKeyProp];}
117                         set {
118                                 base[decryptionKeyProp] = value;
119                                 SetDecryptionKey (value);
120                         }
121                 }
122
123                 // property exists for backward compatibility
124                 public MachineKeyValidation Validation {
125                         get { return validation; }
126                         set {
127                                 if (value == MachineKeyValidation.Custom)
128                                         throw new ArgumentException ();
129
130                                 string algo = value.ToString ();
131                                 // enum and accept values differs for TripleDES
132                                 ValidationAlgorithm = (algo == "TripleDES") ? "3DES" : algo;
133                         }
134                 }
135
136                 [StringValidator (MinLength = 1)]
137                 [TypeConverter (typeof (WhiteSpaceTrimStringConverter))]
138                 [ConfigurationProperty ("validation", DefaultValue = "HMACSHA256")]
139                 public string ValidationAlgorithm {
140                         get { return (string) base [validationProp];}
141                         set {
142                                 if (value == null)
143                                         return;
144
145                                 if (value.StartsWith ("alg:"))
146                                         validation = MachineKeyValidation.Custom;
147                                 else
148                                         validation = (MachineKeyValidation) converter.ConvertFrom (null, null, value);
149
150                                 base[validationProp] = value;
151                         }
152                 }
153
154                 [TypeConverter (typeof (WhiteSpaceTrimStringConverter))]
155                 [StringValidator (MinLength = 1)]
156                 [ConfigurationProperty ("validationKey", DefaultValue = "AutoGenerate,IsolateApps")]
157                 public string ValidationKey {
158                         get { return (string) base [validationKeyProp];}
159                         set {
160                                 base[validationKeyProp] = value;
161                                 SetValidationKey (value);
162                         }
163                 }
164
165                 protected internal override ConfigurationPropertyCollection Properties {
166                         get { return properties; }
167                 }
168
169
170                 internal static MachineKeySection Config {
171                         get { return WebConfigurationManager.GetSection ("system.web/machineKey") as MachineKeySection; }
172                 }
173
174                 byte[] decryption_key;
175                 byte[] validation_key;
176                 SymmetricAlgorithm decryption_template;
177                 KeyedHashAlgorithm validation_template;
178
179                 internal SymmetricAlgorithm GetDecryptionAlgorithm ()
180                 {
181                         // code location to help with unit testing the code
182                         return MachineKeySectionUtils.GetDecryptionAlgorithm (Decryption);
183                 }
184
185                 // not to be reused outside algorithm and key validation purpose
186                 SymmetricAlgorithm DecryptionTemplate {
187                         get {
188                                 if (decryption_template == null)
189                                         decryption_template = GetDecryptionAlgorithm ();
190                                 return decryption_template;
191                         }
192                 }
193
194                 internal byte [] GetDecryptionKey ()
195                 {
196                         if (decryption_key == null)
197                                 SetDecryptionKey (DecryptionKey);
198                         return decryption_key;
199                 }
200
201                 void SetDecryptionKey (string key)
202                 {
203                         if ((key == null) || key.StartsWith ("AutoGenerate")) {
204                                 decryption_key = AutoGenerate (MachineKeyRegistryStorage.KeyType.Encryption);
205                         } else {
206                                 try {
207                                         decryption_key = MachineKeySectionUtils.GetBytes (key, key.Length);
208                                         DecryptionTemplate.Key = decryption_key;
209                                 }
210                                 catch {
211                                         decryption_key = null;
212                                         throw new ArgumentException ("Invalid key length");
213                                 }
214                         }
215                 }
216
217                 internal KeyedHashAlgorithm GetValidationAlgorithm ()
218                 {
219                         // code location to help with unit testing the code
220                         return MachineKeySectionUtils.GetValidationAlgorithm (this);
221                 }
222
223                 // not to be reused outside algorithm and key validation purpose
224                 KeyedHashAlgorithm ValidationTemplate {
225                         get {
226                                 if (validation_template == null)
227                                         validation_template = GetValidationAlgorithm ();
228                                 return validation_template;
229                         }
230                 }
231
232                 internal byte [] GetValidationKey ()
233                 {
234                         if (validation_key == null)
235                                 SetValidationKey (ValidationKey);
236                         return validation_key;
237                 }
238
239                 // key can be expended for HMAC - i.e. a small key, e.g. 32 bytes, is still accepted as valid
240                 // the HMAC class already deals with keys larger than what it can use (digested to right size)
241                 void SetValidationKey (string key)
242                 {
243                         if ((key == null) || key.StartsWith ("AutoGenerate")) {
244                                 validation_key = AutoGenerate (MachineKeyRegistryStorage.KeyType.Validation);
245                         } else {
246                                 try {
247                                         validation_key = MachineKeySectionUtils.GetBytes (key, key.Length);
248                                         ValidationTemplate.Key = validation_key;
249                                 }
250                                 catch (CryptographicException) {
251                                         // second chance, use the key length that the HMAC really wants
252                                         try {
253                                                 byte[] expanded_key = new byte [ValidationTemplate.Key.Length];
254                                                 Array.Copy (validation_key, 0, expanded_key, 0, validation_key.Length);
255                                                 ValidationTemplate.Key = expanded_key;
256                                                 validation_key = expanded_key;
257                                         }
258                                         catch {
259                                                 validation_key = null;
260                                                 throw new ArgumentException ("Invalid key length");
261                                         }
262                                 }
263                         }
264                 }
265
266                 byte[] AutoGenerate (MachineKeyRegistryStorage.KeyType type)
267                 {
268                         byte[] key = null;
269                         try {
270                                 key = MachineKeyRegistryStorage.Retrieve (type);
271
272                                 // ensure the stored key is usable with the selection algorithm
273                                 if (type == MachineKeyRegistryStorage.KeyType.Encryption)
274                                         DecryptionTemplate.Key = key;
275                                 else if (type == MachineKeyRegistryStorage.KeyType.Validation)
276                                         ValidationTemplate.Key = key;
277                         } catch (Exception) {
278                                 key = null;
279                         }
280                         // some algorithms have special needs for key (e.g. length, parity, weak keys...) 
281                         // so we better ask them to provide a default key (than to generate/use bad ones)
282                         if (key == null) {
283                                 if (type == MachineKeyRegistryStorage.KeyType.Encryption)
284                                         key = DecryptionTemplate.Key;
285                                 else if (type == MachineKeyRegistryStorage.KeyType.Validation)
286                                         key = ValidationTemplate.Key;
287                                 MachineKeyRegistryStorage.Store (key, type);
288                         }
289                         return key;
290                 }
291         }
292 }
293