Fix for rare mono runtime crash during shutdown sequence on Windows.
[mono.git] / mcs / class / System / System.Security.Cryptography.X509Certificates / X509EnhancedKeyUsageExtension.cs
1 //
2 // System.Security.Cryptography.X509EnhancedKeyUsageExtension
3 //
4 // Author:
5 //      Sebastien Pouliot  <sebastien@ximian.com>
6 //
7 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 #if SECURITY_DEP
30
31 #if MONO_SECURITY_ALIAS
32 extern alias MonoSecurity;
33 using MonoSecurity::Mono.Security;
34 #else
35 using Mono.Security;
36 #endif
37
38 using System.Text;
39
40 namespace System.Security.Cryptography.X509Certificates {
41
42         public sealed class X509EnhancedKeyUsageExtension : X509Extension {
43
44                 internal const string oid = "2.5.29.37";
45                 internal const string friendlyName = "Enhanced Key Usage";
46
47                 private OidCollection _enhKeyUsage;
48                 private AsnDecodeStatus _status;
49
50                 // constructors
51
52                 public X509EnhancedKeyUsageExtension ()
53                 {
54                         _oid = new Oid (oid, friendlyName);
55                 }
56
57                 public X509EnhancedKeyUsageExtension (AsnEncodedData encodedEnhancedKeyUsages, bool critical)
58                 {
59                         // ignore the Oid provided by encodedKeyUsage (our rules!)
60                         _oid = new Oid (oid, friendlyName);
61                         _raw = encodedEnhancedKeyUsages.RawData;
62                         base.Critical = critical;
63                         _status = Decode (this.RawData);
64                 }
65
66                 public X509EnhancedKeyUsageExtension (OidCollection enhancedKeyUsages, bool critical)
67                 {
68                         if (enhancedKeyUsages == null)
69                                 throw new ArgumentNullException ("enhancedKeyUsages");
70
71                         _oid = new Oid (oid, friendlyName);
72                         base.Critical = critical;
73                         _enhKeyUsage = enhancedKeyUsages.ReadOnlyCopy ();
74                         RawData = Encode ();
75                 }
76
77                 // properties
78
79                 public OidCollection EnhancedKeyUsages {
80                         get {
81                                 switch (_status) {
82                                 case AsnDecodeStatus.Ok:
83                                 case AsnDecodeStatus.InformationNotAvailable:
84                                         if (_enhKeyUsage == null)
85                                                 _enhKeyUsage = new OidCollection ();
86                                         _enhKeyUsage.ReadOnly = true;
87                                         return _enhKeyUsage;
88                                 default:
89                                         throw new CryptographicException ("Badly encoded extension.");
90                                 }
91                         }
92                 }
93
94                 // methods
95
96                 public override void CopyFrom (AsnEncodedData asnEncodedData) 
97                 {
98                         if (asnEncodedData == null)
99                                 throw new ArgumentNullException ("encodedData");
100
101                         X509Extension ex = (asnEncodedData as X509Extension);
102                         if (ex == null)
103                                 throw new ArgumentException (Locale.GetText ("Wrong type."), "asnEncodedData");
104
105                         if (ex._oid == null)
106                                 _oid = new Oid (oid, friendlyName);
107                         else 
108                                 _oid = new Oid (ex._oid);
109
110                         RawData = ex.RawData;
111                         base.Critical = ex.Critical;
112                         // and we deal with the rest later
113                         _status = Decode (this.RawData);
114                 }
115
116                 // internal
117
118                 internal AsnDecodeStatus Decode (byte[] extension)
119                 {
120                         if ((extension == null) || (extension.Length == 0))
121                                 return AsnDecodeStatus.BadAsn;
122                         if (extension [0] != 0x30)
123                                 return AsnDecodeStatus.BadTag;
124
125                         if (_enhKeyUsage == null)
126                                 _enhKeyUsage = new OidCollection ();
127
128                         try {
129                                 ASN1 ex = new ASN1 (extension);
130                                 if (ex.Tag != 0x30)
131                                         throw new CryptographicException (Locale.GetText ("Invalid ASN.1 Tag"));
132                                 for (int i=0; i < ex.Count; i++) {
133                                         _enhKeyUsage.Add (new Oid (ASN1Convert.ToOid (ex [i])));
134                                 }
135                         }
136                         catch {
137                                 return AsnDecodeStatus.BadAsn;
138                         }
139
140                         return AsnDecodeStatus.Ok;
141                 }
142
143                 internal byte[] Encode ()
144                 {
145                         ASN1 ex = new ASN1 (0x30);
146                         foreach (Oid oid in _enhKeyUsage) {
147                                 ex.Add (ASN1Convert.FromOid (oid.Value));
148                         }
149                         return ex.GetBytes ();
150                 }
151
152                 internal override string ToString (bool multiLine)
153                 {
154                         switch (_status) {
155                         case AsnDecodeStatus.BadAsn:
156                                 return String.Empty;
157                         case AsnDecodeStatus.BadTag:
158                         case AsnDecodeStatus.BadLength:
159                                 return FormatUnkownData (_raw);
160                         case AsnDecodeStatus.InformationNotAvailable:
161                                 return "Information Not Available";
162                         }
163
164                         if (_oid.Value != oid)
165                                 return String.Format ("Unknown Key Usage ({0})", _oid.Value);
166                         if (_enhKeyUsage.Count == 0)
167                                 return "Information Not Available";
168
169                         StringBuilder sb = new StringBuilder ();
170
171                         for (int i=0; i < _enhKeyUsage.Count; i++) {
172                                 Oid o = _enhKeyUsage [i];
173                                 switch (o.Value) {
174                                 case "1.3.6.1.5.5.7.3.1":
175                                         sb.Append ("Server Authentication (");
176                                         break;
177                                 default:
178                                         sb.Append ("Unknown Key Usage (");
179                                         break;
180                                 }
181                                 sb.Append (o.Value);
182                                 sb.Append (")");
183
184                                 if (multiLine)
185                                         sb.Append (Environment.NewLine);
186                                 else if (i != (_enhKeyUsage.Count - 1))
187                                         sb.Append (", ");
188                         }
189
190                         return sb.ToString ();
191                 }
192         }
193 }
194
195 #endif