Merge pull request #2274 from esdrubal/udpclientreceive
[mono.git] / mcs / class / corlib / System.Security.Cryptography.X509Certificates / X509Certificate.cs
index 0722b818517dab6c8fd6546e8472f332f2e9ce32..144997e573b63c0cb211a47596cdbb0e676228ac 100644 (file)
@@ -35,12 +35,8 @@ using System.Text;
 using Mono.Security;
 using Mono.Security.X509;
 
-#if NET_2_0
 using System.Runtime.Serialization;
-#endif
-#if !NET_2_1
 using Mono.Security.Authenticode;
-#endif
 
 namespace System.Security.Cryptography.X509Certificates {
 
@@ -54,72 +50,27 @@ namespace System.Security.Cryptography.X509Certificates {
        [Serializable]
 #if NET_2_1
        public partial class X509Certificate {
-#elif NET_2_0
-       public partial class X509Certificate : IDeserializationCallback, ISerializable {
 #else
-       public class X509Certificate {
+       public partial class X509Certificate : IDeserializationCallback, ISerializable {
 #endif
-               // typedef struct _CERT_CONTEXT {
-                //     DWORD                   dwCertEncodingType;
-                //     BYTE                    *pbCertEncoded;
-               //      DWORD                   cbCertEncoded;
-               //      PCERT_INFO              pCertInfo;
-               //      HCERTSTORE              hCertStore;
-               // } CERT_CONTEXT, *PCERT_CONTEXT;
-               // typedef const CERT_CONTEXT *PCCERT_CONTEXT;
-               [StructLayout (LayoutKind.Sequential)]
-               internal struct CertificateContext {
-                       public UInt32 dwCertEncodingType;
-                       public IntPtr pbCertEncoded;
-                       public UInt32 cbCertEncoded;
-                       public IntPtr pCertInfo;
-                       public IntPtr hCertStore;
-               }
-               // NOTE: We only define the CryptoAPI structure (from WINCRYPT.H)
-               // so we don't create any dependencies on Windows DLL in corlib
+               X509CertificateImpl impl;
 
-               private Mono.Security.X509.X509Certificate x509;
                private bool hideDates;
-               private byte[] cachedCertificateHash;
-       
-               // almost every byte[] returning function has a string equivalent
-               // sadly the BitConverter insert dash between bytes :-(
-               private string tostr (byte[] data) 
-               {
-                       if (data != null) {
-                               StringBuilder sb = new StringBuilder ();
-                               for (int i = 0; i < data.Length; i++)
-                                       sb.Append (data[i].ToString ("X2"));
-                               return sb.ToString ();
-                       }
-                       else
-                               return null;
-               }
        
                // static methods
        
                public static X509Certificate CreateFromCertFile (string filename) 
                {
-                       byte[] data = Load (filename);
+                       byte[] data = File.ReadAllBytes (filename);
                        return new X509Certificate (data);
                }
 
-#if !NET_2_1
                [MonoTODO ("Incomplete - minimal validation in this version")]
                public static X509Certificate CreateFromSignedFile (string filename)
                {
                        try {
                                AuthenticodeDeformatter a = new AuthenticodeDeformatter (filename);
                                if (a.SigningCertificate != null) {
-#if !NET_2_0
-                                       // before 2.0 the signing certificate is returned only if the signature is valid
-                                       if (a.Reason != 0) {
-                                               string msg = String.Format (Locale.GetText (
-                                                       "Invalid digital signature on {0}, reason #{1}."),
-                                                       filename, a.Reason);
-                                               throw new COMException (msg);
-                                       }
-#endif
                                        return new X509Certificate (a.SigningCertificate.RawData);
                                }
                        }
@@ -127,27 +78,13 @@ namespace System.Security.Cryptography.X509Certificates {
                                // don't wrap SecurityException into a COMException
                                throw;
                        }
-#if !NET_2_0
-                       catch (COMException) {
-                               // don't wrap COMException into a COMException
-                               throw;
-                       }
-#endif
                        catch (Exception e) {
                                string msg = Locale.GetText ("Couldn't extract digital signature from {0}.", filename);
                                throw new COMException (msg, e);
                        }
-#if NET_2_0
                        throw new CryptographicException (Locale.GetText ("{0} isn't signed.", filename));
-#else
-                       // if no signature is present return an empty certificate
-                       byte[] cert = null; // must not confuse compiler about null ;)
-                       return new X509Certificate (cert);
-#endif
                }
 
-#endif // NET_2_1
-
                // constructors
        
                // special constructor for Publisher (and related classes).
@@ -155,11 +92,7 @@ namespace System.Security.Cryptography.X509Certificates {
                internal X509Certificate (byte[] data, bool dates) 
                {
                        if (data != null) {
-#if NET_2_0
                                Import (data, (string)null, X509KeyStorageFlags.DefaultKeySet);
-#else
-                               x509 = new Mono.Security.X509.X509Certificate (data);
-#endif
                                hideDates = !dates;
                        }
                }
@@ -167,42 +100,24 @@ namespace System.Security.Cryptography.X509Certificates {
                public X509Certificate (byte[] data) : this (data, true)
                {
                }
-       
+
                public X509Certificate (IntPtr handle) 
                {
-#if NET_2_0
                        if (handle == IntPtr.Zero)
                                throw new ArgumentException ("Invalid handle.");
-#endif
-                       InitFromHandle (handle);
-               }
 
-               [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
-               private void InitFromHandle (IntPtr handle)
-               {
-                       if (handle != IntPtr.Zero) {
-                               // both Marshal.PtrToStructure and Marshal.Copy use LinkDemand (so they will always success from here)
-                               CertificateContext cc = (CertificateContext) Marshal.PtrToStructure (handle, typeof (CertificateContext));
-                               byte[] data = new byte [cc.cbCertEncoded];
-                               Marshal.Copy (cc.pbCertEncoded, data, 0, (int)cc.cbCertEncoded);
-                               x509 = new Mono.Security.X509.X509Certificate (data);
-                       }
-                       // for 1.x IntPtr.Zero results in an "empty" certificate instance
+                       impl = X509Helper.InitFromHandle (handle);
                }
-       
+
                public X509Certificate (System.Security.Cryptography.X509Certificates.X509Certificate cert) 
                {
-#if NET_2_0
                        if (cert == null)
                                throw new ArgumentNullException ("cert");
-#endif
 
-                       if (cert != null) {
-                               byte[] data = cert.GetRawCertData ();
-                               if (data != null)
-                                       x509 = new Mono.Security.X509.X509Certificate (data);
-                               hideDates = false;
-                       }
+                       X509Helper.ThrowIfContextInvalid (cert.impl);
+
+                       impl = X509Helper.InitFromCertificate (cert.impl);
+                       hideDates = false;
                }
 
 
@@ -213,59 +128,30 @@ namespace System.Security.Cryptography.X509Certificates {
                        if (other == null) {
                                return false;
                        } else {
-                               if (other.x509 == null) {
-#if NET_2_0
-                                       if (x509 == null)
+                               if (!X509Helper.IsValid (other.impl)) {
+                                       if (!X509Helper.IsValid (impl))
                                                return true;
                                        throw new CryptographicException (Locale.GetText ("Certificate instance is empty."));
-#else
-                                       return (x509 == null);
-#endif
                                }
 
-                               byte[] raw = other.x509.RawData;
-                               if (raw != null) {
-                                       if (x509 == null)
-                                               return false;
-                                       if (x509.RawData == null)
-                                               return false;
-                                       if (raw.Length == x509.RawData.Length) {
-                                               for (int i = 0; i < raw.Length; i++) {
-                                                       if (raw[i] != x509.RawData [i])
-                                                               return false;
-                                               }
-                                               // well no choice must be equals!
-                                               return true;
-                                       }
-                                       else
-                                               return false;
-                               }
+                               return X509CertificateImpl.Equals (impl, other.impl);
                        }
-                       return ((x509 == null) || (x509.RawData == null));
                }
-       
+
                // LAMESPEC: This is the equivalent of the "thumbprint" that can be seen
                // in the certificate viewer of Windows. This is ALWAYS the SHA1 hash of
                // the certificate (i.e. it has nothing to do with the actual hash 
                // algorithm used to sign the certificate).
                public virtual byte[] GetCertHash () 
                {
-#if NET_2_0
-                       if (x509 == null)
-                               throw new CryptographicException (Locale.GetText ("Certificate instance is empty."));
-#endif
-                       // we'll hash the cert only once and only if required
-                       if ((cachedCertificateHash == null) && (x509 != null)) {
-                               SHA1 sha = SHA1.Create ();
-                               cachedCertificateHash = sha.ComputeHash (x509.RawData);
-                       }
-                       return cachedCertificateHash;
+                       X509Helper.ThrowIfContextInvalid (impl);
+                       return impl.GetCertHash ();
                }
        
                public virtual string GetCertHashString () 
                {
                        // must call GetCertHash (not variable) or optimization wont work
-                       return tostr (GetCertHash ());
+                       return X509Helper.ToHexString (GetCertHash ());
                }
        
                // strangly there are no DateTime returning function
@@ -273,16 +159,9 @@ namespace System.Security.Cryptography.X509Certificates {
                {
                        if (hideDates)
                                return null;
-#if NET_2_0
-                       if (x509 == null)
-                               throw new CryptographicException (Locale.GetText ("Certificate instance is empty."));
+                       X509Helper.ThrowIfContextInvalid (impl);
 
-                       return x509.ValidFrom.ToLocalTime ().ToString ();
-#else
-                       // LAMESPEC: Microsoft returns the local time from Pacific Time (GMT-8)
-                       // BUG: This will not be corrected in Framework 1.1 and also affect WSE 1.0
-                       return x509.ValidFrom.ToUniversalTime ().AddHours (-8).ToString ();
-#endif
+                       return impl.GetEffectiveDateString ().ToString ();
                }
        
                // strangly there are no DateTime returning function
@@ -290,16 +169,9 @@ namespace System.Security.Cryptography.X509Certificates {
                {
                        if (hideDates)
                                return null;
-#if NET_2_0
-                       if (x509 == null)
-                               throw new CryptographicException (Locale.GetText ("Certificate instance is empty."));
+                       X509Helper.ThrowIfContextInvalid (impl);
 
-                       return x509.ValidUntil.ToLocalTime ().ToString ();
-#else
-                       // LAMESPEC: Microsoft returns the local time from Pacific Time (GMT-8)
-                       // BUG: This will not be corrected in Framework 1.1 and also affect WSE 1.0
-                       return x509.ValidUntil.ToUniversalTime ().AddHours (-8).ToString ();
-#endif
+                       return impl.GetExpirationDateString ().ToString ();
                }
        
                // well maybe someday there'll be support for PGP or SPKI ?
@@ -310,128 +182,81 @@ namespace System.Security.Cryptography.X509Certificates {
        
                public override int GetHashCode ()
                {
-#if NET_2_0
-                       if (x509 == null)
-                               return 0;
-#endif
-                       // the cert hash may not be (yet) calculated
-                       if (cachedCertificateHash == null)
-                               GetCertHash();
-               
-                       // return the integer of the first 4 bytes of the cert hash
-                       if ((cachedCertificateHash != null) && (cachedCertificateHash.Length >= 4))
-                               return ((cachedCertificateHash[0] << 24) |(cachedCertificateHash[1] << 16) |
-                                       (cachedCertificateHash[2] << 8) | cachedCertificateHash[3]);
-                       else
+                       if (!X509Helper.IsValid (impl))
                                return 0;
+                       return impl.GetHashCode ();
                }
 
-#if NET_2_0
                [Obsolete ("Use the Issuer property.")]
-#endif
                public virtual string GetIssuerName () 
                {
-#if NET_2_0
-                       if (x509 == null)
-                               throw new CryptographicException (Locale.GetText ("Certificate instance is empty."));
-#endif
-                       return x509.IssuerName;
+                       X509Helper.ThrowIfContextInvalid (impl);
+                       return impl.GetIssuerName (true);
                }
        
                public virtual string GetKeyAlgorithm () 
                {
-#if NET_2_0
-                       if (x509 == null)
-                               throw new CryptographicException (Locale.GetText ("Certificate instance is empty."));
-#endif
-                       return x509.KeyAlgorithm;
+                       X509Helper.ThrowIfContextInvalid (impl);
+                       return impl.GetKeyAlgorithm ();
                }
        
                public virtual byte[] GetKeyAlgorithmParameters () 
                {
-#if NET_2_0
-                       if (x509 == null)
-                               throw new CryptographicException (Locale.GetText ("Certificate instance is empty."));
+                       X509Helper.ThrowIfContextInvalid (impl);
 
-                       byte[] kap = x509.KeyAlgorithmParameters;
+                       byte[] kap = impl.GetKeyAlgorithmParameters ();
                        if (kap == null)
                                throw new CryptographicException (Locale.GetText ("Parameters not part of the certificate"));
 
                        return kap;
-#else
-                       return x509.KeyAlgorithmParameters;
-#endif
                }
        
                public virtual string GetKeyAlgorithmParametersString () 
                {
-                       return tostr (GetKeyAlgorithmParameters ());
+                       return X509Helper.ToHexString (GetKeyAlgorithmParameters ());
                }
        
-#if NET_2_0
                [Obsolete ("Use the Subject property.")]
-#endif
                public virtual string GetName ()
                {
-#if NET_2_0
-                       if (x509 == null)
-                               throw new CryptographicException (Locale.GetText ("Certificate instance is empty."));
-#endif
-                       return x509.SubjectName;
+                       X509Helper.ThrowIfContextInvalid (impl);
+                       return impl.GetSubjectName (true);
                }
        
                public virtual byte[] GetPublicKey () 
                {
-#if NET_2_0
-                       if (x509 == null)
-                               throw new CryptographicException (Locale.GetText ("Certificate instance is empty."));
-#endif
-                       return x509.PublicKey;
+                       X509Helper.ThrowIfContextInvalid (impl);
+                       return impl.GetPublicKey ();
                }
        
                public virtual string GetPublicKeyString () 
                {
-                       return tostr (GetPublicKey ());
+                       return X509Helper.ToHexString (GetPublicKey ());
                }
        
                public virtual byte[] GetRawCertData () 
                {
-#if NET_2_0
-                       if (x509 == null)
-                               throw new CryptographicException (Locale.GetText ("Certificate instance is empty."));
-                       return x509.RawData;
-#else
-                       return ((x509 != null) ? x509.RawData : null);
-#endif
+                       X509Helper.ThrowIfContextInvalid (impl);
+                       return impl.GetRawCertData ();
                }
        
                public virtual string GetRawCertDataString () 
                {
-#if NET_2_0
-                       if (x509 == null)
-                               throw new CryptographicException (Locale.GetText ("Certificate instance is empty."));
-                       return tostr (x509.RawData);
-#else
-                       return ((x509 != null) ? tostr (x509.RawData) : null);
-#endif
+                       X509Helper.ThrowIfContextInvalid (impl);
+                       return X509Helper.ToHexString (impl.GetRawCertData ());
                }
        
                public virtual byte[] GetSerialNumber () 
                {
-#if NET_2_0
-                       if (x509 == null)
-                               throw new CryptographicException (Locale.GetText ("Certificate instance is empty."));
-#endif
-                       return x509.SerialNumber;
+                       X509Helper.ThrowIfContextInvalid (impl);
+                       return impl.GetSerialNumber ();
                }
        
                public virtual string GetSerialNumberString () 
                {
                        byte[] sn = GetSerialNumber ();
-#if NET_2_0
                        Array.Reverse (sn);
-#endif
-                       return tostr (sn);
+                       return X509Helper.ToHexString (sn);
                }
        
                // to please corcompare ;-)
@@ -442,70 +267,15 @@ namespace System.Security.Cryptography.X509Certificates {
        
                public virtual string ToString (bool fVerbose) 
                {
-                       if (!fVerbose || (x509 == null))
+                       if (!fVerbose || !X509Helper.IsValid (impl))
                                return base.ToString ();
 
-                       string nl = Environment.NewLine;
-                       StringBuilder sb = new StringBuilder ();
-#if NET_2_0
-                       sb.AppendFormat ("[Subject]{0}  {1}{0}{0}", nl, Subject);
-                       sb.AppendFormat ("[Issuer]{0}  {1}{0}{0}", nl, Issuer);
-                       sb.AppendFormat ("[Not Before]{0}  {1}{0}{0}", nl, GetEffectiveDateString ());
-                       sb.AppendFormat ("[Not After]{0}  {1}{0}{0}", nl, GetExpirationDateString ());
-                       sb.AppendFormat ("[Thumbprint]{0}  {1}{0}", nl, GetCertHashString ());
-#else
-                       sb.Append ("CERTIFICATE:");
-                       sb.Append (nl);
-                       sb.Append ("\tFormat:  ");
-                       sb.Append (GetFormat ());
-                       if (x509.SubjectName != null) {
-                               sb.Append (nl);
-                               sb.Append ("\tName:  ");
-                               sb.Append (GetName ());
-                       }
-                       if (x509.IssuerName != null) {
-                               sb.Append (nl);
-                               sb.Append ("\tIssuing CA:  ");
-                               sb.Append (GetIssuerName ());
-                       }
-                       if (x509.SignatureAlgorithm != null) {
-                               sb.Append (nl);
-                               sb.Append ("\tKey Algorithm:  ");
-                               sb.Append (GetKeyAlgorithm ());
-                       }
-                       if (x509.SerialNumber != null) {
-                               sb.Append (nl);
-                               sb.Append ("\tSerial Number:  ");
-                               sb.Append (GetSerialNumberString ());
-                       }
-                       // Note: Algorithm is not spelled right as the actual 
-                       // MS implementation (we do exactly the same for the
-                       // comparison in the unit tests)
-                       if (x509.KeyAlgorithmParameters != null) {
-                               sb.Append (nl);
-                               sb.Append ("\tKey Alogrithm Parameters:  ");
-                               sb.Append (GetKeyAlgorithmParametersString ());
-                       }
-                       if (x509.PublicKey != null) {
-                               sb.Append (nl);
-                               sb.Append ("\tPublic Key:  ");
-                               sb.Append (GetPublicKeyString ());
-                       }
-                       sb.Append (nl);
-#endif
-                       sb.Append (nl);
-                       return sb.ToString ();
+                       return impl.ToString (true);
                }
 
-               private static byte[] Load (string fileName)
+               protected static string FormatDate (DateTime date)
                {
-                       byte[] data = null;
-                       using (FileStream fs = File.OpenRead (fileName)) {
-                               data = new byte [fs.Length];
-                               fs.Read (data, 0, data.Length);
-                               fs.Close ();
-                       }
-                       return data;
+                       throw new NotImplementedException ();
                }
        }
 }