2 // X509Certificates.cs: Handles (a little better) X509 certificates.
5 // Sebastien Pouliot (spouliot@motus.com)
7 // (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
11 using System.ComponentModel;
12 using System.Security.Cryptography;
13 using System.Security.Cryptography.X509Certificates;
16 using MX = Mono.Security.X509;
17 using Mono.Security.X509.Extensions;
19 namespace Microsoft.Web.Services.Security.X509 {
21 public sealed class X509Certificate : System.Security.Cryptography.X509Certificates.X509Certificate, IDisposable {
23 // do not includes: KeyUsage.keyEncipherment and KeyUsage.keyAgreement (see "OWN.cer")
24 private static KeyUsages[] dataEncryption = new KeyUsages [3] { KeyUsages.dataEncipherment, KeyUsages.decipherOnly, KeyUsages.encipherOnly };
25 // do not includes KeyUsage.cRLSign, KeyUsage.keyCertSign
26 private static KeyUsages[] digitalSignature = new KeyUsages [2] { KeyUsages.digitalSignature, KeyUsages.nonRepudiation };
28 private MX.X509Certificate x509;
29 private bool m_disposed;
31 public X509Certificate (byte[] rawCertificate) : base (rawCertificate)
33 x509 = new MX.X509Certificate (rawCertificate);
37 public X509Certificate (IntPtr handle) : base (handle)
39 x509 = new MX.X509Certificate (base.GetRawCertData ());
49 public void Dispose ()
52 // Finalization is now unnecessary
53 GC.SuppressFinalize (this);
56 // no need as they all are abstract before us
60 // LAMESPEC: Do not confuse with CreateFromCertFile
61 public static X509Certificate CreateCertFromFile (string fileName)
63 System.Security.Cryptography.X509Certificates.X509Certificate x = System.Security.Cryptography.X509Certificates.X509Certificate.CreateFromCertFile (fileName);
64 return new X509Certificate (x.GetRawCertData ());
67 // LAMESPEC: Do not confuse with CreateFromSignedFile
68 public static X509Certificate CreateCertFromSignedFile (string fileName)
70 System.Security.Cryptography.X509Certificates.X509Certificate x = System.Security.Cryptography.X509Certificates.X509Certificate.CreateFromSignedFile (fileName);
71 return new X509Certificate (x.GetRawCertData ());
74 // I knew that using string for date were a bad idea!
75 public bool IsCurrent {
76 get { return x509.IsCurrent; }
79 // Well it seems that DSA certificates aren't popular enough :-(
80 // Note: Private key isn't available
81 [MonoTODO("Private key isn't yet supported - requires cert stores")]
84 throw new Win32Exception (0, "Private key is unavailable (TODO)");
88 // Well it seems that DSA certificates aren't popular enough :-(
89 public RSA PublicKey {
90 get { return x509.RSA; }
93 // Just KeyUsage or also ExtendedKeyUsage ?
94 // it doesn't seems to interpret NetscapeCertType
95 private bool Supports (KeyUsages[] usages)
98 MX.X509Extension extn = x509.Extensions ["2.5.29.15"];
100 KeyUsageExtension keyUsage = new KeyUsageExtension (extn);
101 foreach (KeyUsages usage in usages) {
102 if (keyUsage.Support (usage))
107 // DEPRECATED keyAttributes
108 extn = x509.Extensions ["2.5.29.2"];
110 KeyAttributesExtension keyAttr = new KeyAttributesExtension (extn);
111 foreach (KeyUsages usage in usages) {
112 if (keyAttr.Support (usage))
117 // key usage isn't specified (so it's not limited)
121 public bool SupportsDataEncryption {
123 // always true for older certificates
124 if (x509.Version < 3)
126 return Supports (dataEncryption);
130 public bool SupportsDigitalSignature {
132 // always true for older certificates
133 if (x509.Version < 3)
135 return Supports (digitalSignature);
139 public static X509Certificate FromBase64String (string rawString)
141 byte[] cert = Convert.FromBase64String (rawString);
142 return new X509Certificate (cert);
145 public byte[] GetKeyIdentifier ()
147 // if present in certificate return value of the SubjectKeyIdentifier
148 MX.X509Extension extn = x509.Extensions ["2.5.29.14"];
150 ASN1 bs = new ASN1 (extn.Value.Value);
153 // strangely DEPRECATED keyAttributes isn't used here (like KeyUsage)
155 // if not then we must calculate the SubjectKeyIdentifier ourselve
156 // Note: MS does that hash on the complete subjectPublicKeyInfo (unlike PKIX)
157 // http://groups.google.ca/groups?selm=e7RqM%24plCHA.1488%40tkmsftngp02&oe=UTF-8&output=gplain
158 ASN1 subjectPublicKeyInfo = new ASN1 (0x30);
159 ASN1 algo = subjectPublicKeyInfo.Add (new ASN1 (0x30));
160 algo.Add (new ASN1 (CryptoConfig.EncodeOID (x509.KeyAlgorithm)));
161 // FIXME: does it work for DSA certs (without an 2.5.29.14 extension ?)
162 algo.Add (new ASN1 (x509.KeyAlgorithmParameters));
163 byte[] pubkey = x509.PublicKey;
164 byte[] bsvalue = new byte [pubkey.Length + 1]; // add unused bits (0) before the public key
165 Array.Copy (pubkey, 0, bsvalue, 1, pubkey.Length);
166 subjectPublicKeyInfo.Add (new ASN1 (0x03, bsvalue));
167 SHA1 sha = SHA1.Create ();
168 return sha.ComputeHash (subjectPublicKeyInfo.GetBytes ());
171 public string GetSubjectAlternativeName ()
173 // if present in certificate return value of the SubjectAltName
174 MX.X509Extension extn = x509.Extensions ["2.5.29.17"];
177 SubjectAltNameExtension altname = new SubjectAltNameExtension (extn);
178 return ((altname.RFC822.Length > 0) ? altname.RFC822 [0] : null);
181 // overloaded but WHY ?
182 public override int GetHashCode ()
184 return base.GetHashCode ();
187 public string ToBase64String ()
189 return Convert.ToBase64String (base.GetRawCertData ());