Automatic optimization bug bisector.
[mono.git] / mcs / class / System / System.Security.Cryptography.X509Certificates / X509BasicConstraintsExtension.cs
1 //
2 // System.Security.Cryptography.X509BasicConstraintsExtension
3 //
4 // Author:
5 //      Sebastien Pouliot  <sebastien@ximian.com>
6 //      Tim Coleman (tim@timcoleman.com)
7 //
8 // (C) 2003 Motus Technologies Inc. (http://www.motus.com)
9 // Copyright (C) Tim Coleman, 2004
10 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
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 #if SECURITY_DEP
33
34 #if MONOTOUCH || MONODROID
35 using Mono.Security;
36 #else
37 extern alias MonoSecurity;
38 using MonoSecurity::Mono.Security;
39 #endif
40
41 using System.Text;
42
43 namespace System.Security.Cryptography.X509Certificates {
44
45         public sealed class X509BasicConstraintsExtension : X509Extension {
46
47                 internal const string oid = "2.5.29.19";
48                 internal const string friendlyName = "Basic Constraints";
49
50                 private bool _certificateAuthority;
51                 private bool _hasPathLengthConstraint;
52                 private int _pathLengthConstraint;
53                 private AsnDecodeStatus _status;
54
55                 // constructors
56
57                 public X509BasicConstraintsExtension ()
58                 {
59                         _oid = new Oid (oid, friendlyName);
60                 }
61
62                 public X509BasicConstraintsExtension (AsnEncodedData encodedBasicConstraints, bool critical)
63                 {
64                         // ignore the Oid provided by encodedKeyUsage (our rules!)
65                         _oid = new Oid (oid, friendlyName);
66                         _raw = encodedBasicConstraints.RawData;
67                         base.Critical = critical;
68                         _status = Decode (this.RawData);
69                 }
70
71                 public X509BasicConstraintsExtension (bool certificateAuthority, bool hasPathLengthConstraint, int pathLengthConstraint, bool critical)
72                 {
73                         if (hasPathLengthConstraint) {
74                                 if (pathLengthConstraint < 0)
75                                         throw new ArgumentOutOfRangeException ("pathLengthConstraint");
76                                 _pathLengthConstraint = pathLengthConstraint;
77                         }
78                         _hasPathLengthConstraint = hasPathLengthConstraint;
79                         _certificateAuthority = certificateAuthority;
80                         _oid = new Oid (oid, friendlyName);
81                         base.Critical = critical;
82                         RawData = Encode ();
83                 }
84
85                 // properties
86
87                 public bool CertificateAuthority {
88                         get {
89                                 switch (_status) {
90                                 case AsnDecodeStatus.Ok:
91                                 case AsnDecodeStatus.InformationNotAvailable:
92                                         return _certificateAuthority;
93                                 default:
94                                         throw new CryptographicException ("Badly encoded extension.");
95                                 }
96                         }
97                 }
98
99                 public bool HasPathLengthConstraint {
100                         get {
101                                 switch (_status) {
102                                 case AsnDecodeStatus.Ok:
103                                 case AsnDecodeStatus.InformationNotAvailable:
104                                         return _hasPathLengthConstraint;
105                                 default:
106                                         throw new CryptographicException ("Badly encoded extension.");
107                                 }
108                         }
109                 }
110
111                 public int PathLengthConstraint {
112                         get {
113                                 switch (_status) {
114                                 case AsnDecodeStatus.Ok:
115                                 case AsnDecodeStatus.InformationNotAvailable:
116                                         return _pathLengthConstraint;
117                                 default:
118                                         throw new CryptographicException ("Badly encoded extension.");
119                                 }
120                         }
121                 }
122
123                 // methods
124
125                 public override void CopyFrom (AsnEncodedData asnEncodedData) 
126                 {
127                         if (asnEncodedData == null)
128                                 throw new ArgumentNullException ("asnEncodedData");
129
130                         X509Extension ex = (asnEncodedData as X509Extension);
131                         if (ex == null)
132                                 throw new ArgumentException (Locale.GetText ("Wrong type."), "asnEncodedData");
133
134                         if (ex._oid == null)
135                                 _oid = new Oid (oid, friendlyName);
136                         else 
137                                 _oid = new Oid (ex._oid);
138
139                         RawData = ex.RawData;
140                         base.Critical = ex.Critical;
141                         // and we deal with the rest later
142                         _status = Decode (this.RawData);
143                 }
144
145                 // internal
146
147                 internal AsnDecodeStatus Decode (byte[] extension)
148                 {
149                         if ((extension == null) || (extension.Length == 0))
150                                 return AsnDecodeStatus.BadAsn;
151                         if (extension [0] != 0x30)
152                                 return AsnDecodeStatus.BadTag;
153                         if (extension.Length < 3) {
154                                 if (!((extension.Length == 2) && (extension [1] == 0x00)))
155                                         return AsnDecodeStatus.BadLength;
156                         }
157
158                         try {
159                                 ASN1 sequence = new ASN1 (extension);
160                                 int n = 0;
161                                 ASN1 a = sequence [n++];
162                                 if ((a != null) && (a.Tag == 0x01)) {
163                                         _certificateAuthority = (a.Value [0] == 0xFF);
164                                         a = sequence [n++];
165                                 }
166                                 if ((a != null) && (a.Tag == 0x02)) {
167                                         _hasPathLengthConstraint = true;
168                                         _pathLengthConstraint = ASN1Convert.ToInt32 (a);
169                                 }
170                         }
171                         catch {
172                                 return AsnDecodeStatus.BadAsn;
173                         }
174
175                         return AsnDecodeStatus.Ok;
176                 }
177
178                 internal byte[] Encode ()
179                 {
180                         ASN1 ex = new ASN1 (0x30);
181
182                         if (_certificateAuthority)
183                                 ex.Add (new ASN1 (0x01, new byte[] { 0xFF }));
184                         if (_hasPathLengthConstraint) {
185                                 // MS encodes the 0 (pathLengthConstraint is OPTIONAL)
186                                 // and in a long form (02 00 versus 02 01 00)
187                                 if (_pathLengthConstraint == 0)
188                                         ex.Add (new ASN1 (0x02, new byte[] { 0x00 }));
189                                 else
190                                         ex.Add (ASN1Convert.FromInt32 (_pathLengthConstraint));
191                         }
192
193                         return ex.GetBytes ();
194                 }
195
196                 internal override string ToString (bool multiLine)
197                 {
198                         switch (_status) {
199                         case AsnDecodeStatus.BadAsn:
200                                 return String.Empty;
201                         case AsnDecodeStatus.BadTag:
202                         case AsnDecodeStatus.BadLength:
203                                 return FormatUnkownData (_raw);
204                         case AsnDecodeStatus.InformationNotAvailable:
205                                 return "Information Not Available";
206                         }
207
208                         if (_oid.Value != oid)
209                                 return String.Format ("Unknown Key Usage ({0})", _oid.Value);
210
211                         StringBuilder sb = new StringBuilder ();
212
213                         sb.Append ("Subject Type=");
214                         if (_certificateAuthority)
215                                 sb.Append ("CA");
216                         else
217                                 sb.Append ("End Entity");
218                         if (multiLine)
219                                 sb.Append (Environment.NewLine);
220                         else
221                                 sb.Append (", ");
222
223                         sb.Append ("Path Length Constraint=");
224                         if (_hasPathLengthConstraint) 
225                                 sb.Append (_pathLengthConstraint);
226                         else
227                                 sb.Append ("None");
228                         if (multiLine)
229                                 sb.Append (Environment.NewLine);
230
231                         return sb.ToString ();
232                 }
233         }
234 }
235
236 #endif