2010-04-06 Jb Evain <jbevain@novell.com>
[mcs.git] / class / System / System.Security.Cryptography.X509Certificates / X509KeyUsageExtension.cs
blobd252dded577f0c23d55ed85e2fd73677ecb0d975
1 //
2 // System.Security.Cryptography.X509Certificates.X509KeyUsageExtension
3 //
4 // Authors:
5 // Tim Coleman (tim@timcoleman.com)
6 // Sebastien Pouliot <sebastien@ximian.com>
7 //
8 // Copyright (C) Tim Coleman, 2004
9 // Copyright (C) 2004-2005 Novell Inc. (http://www.novell.com)
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 //
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 //
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 #if NET_2_0 && SECURITY_DEP
33 using System.Text;
35 using Mono.Security;
37 namespace System.Security.Cryptography.X509Certificates {
39 public sealed class X509KeyUsageExtension : X509Extension {
41 internal const string oid = "2.5.29.15";
42 internal const string friendlyName = "Key Usage";
44 internal const X509KeyUsageFlags all = X509KeyUsageFlags.EncipherOnly | X509KeyUsageFlags.CrlSign |
45 X509KeyUsageFlags.KeyCertSign | X509KeyUsageFlags.KeyAgreement | X509KeyUsageFlags.DataEncipherment |
46 X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.NonRepudiation |
47 X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.DecipherOnly;
49 private X509KeyUsageFlags _keyUsages;
50 private AsnDecodeStatus _status;
52 // constructors
54 public X509KeyUsageExtension ()
56 _oid = new Oid (oid, friendlyName);
59 public X509KeyUsageExtension (AsnEncodedData encodedKeyUsage, bool critical)
61 // ignore the Oid provided by encodedKeyUsage (our rules!)
62 _oid = new Oid (oid, friendlyName);
63 _raw = encodedKeyUsage.RawData;
64 base.Critical = critical;
65 _status = Decode (this.RawData);
68 public X509KeyUsageExtension (X509KeyUsageFlags keyUsages, bool critical)
70 _oid = new Oid (oid, friendlyName);
71 base.Critical = critical;
72 _keyUsages = GetValidFlags (keyUsages);
73 RawData = Encode ();
76 // properties
78 public X509KeyUsageFlags KeyUsages {
79 get {
80 switch (_status) {
81 case AsnDecodeStatus.Ok:
82 case AsnDecodeStatus.InformationNotAvailable:
83 return _keyUsages;
84 default:
85 throw new CryptographicException ("Badly encoded extension.");
90 // methods
92 public override void CopyFrom (AsnEncodedData encodedData)
94 if (encodedData == null)
95 throw new ArgumentNullException ("encodedData");
97 X509Extension ex = (encodedData as X509Extension);
98 if (ex == null)
99 throw new ArgumentException (Locale.GetText ("Wrong type."), "encodedData");
101 if (ex._oid == null)
102 _oid = new Oid (oid, friendlyName);
103 else
104 _oid = new Oid (ex._oid);
106 RawData = ex.RawData;
107 base.Critical = ex.Critical;
108 // and we deal with the rest later
109 _status = Decode (this.RawData);
112 // internal
114 internal X509KeyUsageFlags GetValidFlags (X509KeyUsageFlags flags)
116 if ((flags & all) != flags)
117 return (X509KeyUsageFlags) 0;
118 return flags;
121 internal AsnDecodeStatus Decode (byte[] extension)
123 if ((extension == null) || (extension.Length == 0))
124 return AsnDecodeStatus.BadAsn;
125 if (extension [0] != 0x03)
126 return AsnDecodeStatus.BadTag;
127 if (extension.Length < 3)
128 return AsnDecodeStatus.BadLength;
129 if (extension.Length < 4)
130 return AsnDecodeStatus.InformationNotAvailable;
132 try {
133 ASN1 ex = new ASN1 (extension);
134 int kubits = 0;
135 int i = 1; // byte zero has the number of unused bits (ASN1's BITSTRING)
136 while (i < ex.Value.Length)
137 kubits = (kubits << 8) + ex.Value [i++];
139 _keyUsages = GetValidFlags ((X509KeyUsageFlags)kubits);
141 catch {
142 return AsnDecodeStatus.BadAsn;
145 return AsnDecodeStatus.Ok;
148 internal byte[] Encode ()
150 ASN1 ex = null;
151 int kubits = (int)_keyUsages;
152 byte empty = 0;
154 if (kubits == 0) {
155 ex = new ASN1 (0x03, new byte[] { empty });
156 } else {
157 // count empty bits (applicable to first byte only)
158 int ku = ((kubits < Byte.MaxValue) ? kubits : (kubits >> 8));
159 while (((ku & 0x01) == 0x00) && (empty < 8)) {
160 empty++;
161 ku >>= 1;
164 if (kubits <= Byte.MaxValue) {
165 ex = new ASN1 (0x03, new byte[] { empty, (byte)kubits });
166 } else {
167 ex = new ASN1 (0x03, new byte[] { empty, (byte)kubits, (byte)(kubits >> 8) });
171 return ex.GetBytes ();
174 internal override string ToString (bool multiLine)
176 switch (_status) {
177 case AsnDecodeStatus.BadAsn:
178 return String.Empty;
179 case AsnDecodeStatus.BadTag:
180 case AsnDecodeStatus.BadLength:
181 return FormatUnkownData (_raw);
182 case AsnDecodeStatus.InformationNotAvailable:
183 return "Information Not Available";
186 if (_oid.Value != oid)
187 return String.Format ("Unknown Key Usage ({0})", _oid.Value);
188 if (_keyUsages == 0)
189 return "Information Not Available";
191 StringBuilder sb = new StringBuilder ();
193 if ((_keyUsages & X509KeyUsageFlags.DigitalSignature) != 0) {
194 sb.Append ("Digital Signature");
196 if ((_keyUsages & X509KeyUsageFlags.NonRepudiation) != 0) {
197 if (sb.Length > 0)
198 sb.Append (", ");
199 sb.Append ("Non-Repudiation");
201 if ((_keyUsages & X509KeyUsageFlags.KeyEncipherment) != 0) {
202 if (sb.Length > 0)
203 sb.Append (", ");
204 sb.Append ("Key Encipherment");
206 if ((_keyUsages & X509KeyUsageFlags.DataEncipherment) != 0) {
207 if (sb.Length > 0)
208 sb.Append (", ");
209 sb.Append ("Data Encipherment");
211 if ((_keyUsages & X509KeyUsageFlags.KeyAgreement) != 0) {
212 if (sb.Length > 0)
213 sb.Append (", ");
214 sb.Append ("Key Agreement");
216 if ((_keyUsages & X509KeyUsageFlags.KeyCertSign) != 0) {
217 if (sb.Length > 0)
218 sb.Append (", ");
219 sb.Append ("Certificate Signing");
221 if ((_keyUsages & X509KeyUsageFlags.CrlSign) != 0) {
222 if (sb.Length > 0)
223 sb.Append (", ");
224 sb.Append ("Off-line CRL Signing, CRL Signing");
226 if ((_keyUsages & X509KeyUsageFlags.EncipherOnly) != 0) {
227 if (sb.Length > 0)
228 sb.Append (", ");
229 sb.Append ("Encipher Only");
231 if ((_keyUsages & X509KeyUsageFlags.DecipherOnly) != 0) {
232 if (sb.Length > 0)
233 sb.Append (", ");
234 sb.Append ("Decipher Only");
237 int ku = (int)_keyUsages;
238 sb.Append (" (");
239 sb.Append (((byte)ku).ToString ("x2"));
240 if (ku > Byte.MaxValue) {
241 sb.Append (" ");
242 sb.Append (((byte)(ku >> 8)).ToString ("x2"));
244 sb.Append (")");
246 if (multiLine)
247 sb.Append (Environment.NewLine);
249 return sb.ToString ();
254 #endif