//
-// X509Certificates.cs: Handles X.509 certificates.
+// X509Certificate.cs: Handles X.509 certificates.
//
// Author:
-// Sebastien Pouliot (spouliot@motus.com)
+// Sebastien Pouliot <sebastien@ximian.com>
//
// (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
-//
-
-//
-// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2004-2006 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-using System;
using System.IO;
using System.Runtime.InteropServices;
-using System.Security.Cryptography;
+using System.Security.Permissions;
using System.Text;
using Mono.Security;
-using Mono.Security.Authenticode;
using Mono.Security.X509;
-#if !(NET_1_0 || NET_1_1)
using System.Runtime.Serialization;
+#if !MOONLIGHT
+using Mono.Security.Authenticode;
#endif
namespace System.Security.Cryptography.X509Certificates {
// LAMESPEC: the MSDN docs always talks about X509v3 certificates
// and/or Authenticode certs. However this class works with older
// X509v1 certificates and non-authenticode (code signing) certs.
-#if (NET_1_0 || NET_1_1)
[Serializable]
- public class X509Certificate {
+#if NET_2_1
+ public partial class X509Certificate {
#else
- public class X509Certificate : IDeserializationCallback, ISerializable {
+ public partial class X509Certificate : IDeserializationCallback, ISerializable {
#endif
// typedef struct _CERT_CONTEXT {
// DWORD dwCertEncodingType;
public static X509Certificate CreateFromCertFile (string filename)
{
- byte[] data = null;
- FileStream fs = new FileStream (filename, FileMode.Open);
- try {
- data = new byte [fs.Length];
- fs.Read (data, 0, data.Length);
- }
- finally {
- fs.Close ();
- }
-
+ byte[] data = Load (filename);
return new X509Certificate (data);
}
-
+
+#if !MOONLIGHT
[MonoTODO ("Incomplete - minimal validation in this version")]
public static X509Certificate CreateFromSignedFile (string filename)
{
- AuthenticodeDeformatter a = new AuthenticodeDeformatter (filename);
- if (a.SigningCertificate != null) {
- return new X509Certificate (a.SigningCertificate.RawData);
+ try {
+ AuthenticodeDeformatter a = new AuthenticodeDeformatter (filename);
+ if (a.SigningCertificate != null) {
+ return new X509Certificate (a.SigningCertificate.RawData);
+ }
+ }
+ catch (SecurityException) {
+ // don't wrap SecurityException into a COMException
+ throw;
}
- else {
- // if no signature is present return an empty certificate
- byte[] cert = null; // must not confuse compiler about null ;)
- return new X509Certificate (cert);
+ catch (Exception e) {
+ string msg = Locale.GetText ("Couldn't extract digital signature from {0}.", filename);
+ throw new COMException (msg, e);
}
+ throw new CryptographicException (Locale.GetText ("{0} isn't signed.", filename));
}
-
+
+#endif // NET_2_1
+
// constructors
// special constructor for Publisher (and related classes).
internal X509Certificate (byte[] data, bool dates)
{
if (data != null) {
- x509 = new Mono.Security.X509.X509Certificate (data);
+ Import (data, (string)null, X509KeyStorageFlags.DefaultKeySet);
hideDates = !dates;
}
}
- public X509Certificate (byte[] data) : this (data, true) {}
+ public X509Certificate (byte[] data) : this (data, true)
+ {
+ }
public X509Certificate (IntPtr handle)
{
- 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);
+ if (handle == IntPtr.Zero)
+ throw new ArgumentException ("Invalid handle.");
+#if NET_2_1
+ // this works on Windows-only so it's of no use for Moonlight
+ // even more since this ctor is [SecurityCritical]
+ throw new NotSupportedException ();
+#else
+ InitFromHandle (handle);
+#endif
}
+
+#if !MOONLIGHT
+ [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
+ }
+#endif
public X509Certificate (System.Security.Cryptography.X509Certificates.X509Certificate cert)
{
+ if (cert == null)
+ throw new ArgumentNullException ("cert");
+
if (cert != null) {
byte[] data = cert.GetRawCertData ();
if (data != null)
}
}
-#if !(NET_1_0 || NET_1_1)
- public X509Certificate () {}
-
- public X509Certificate (byte[] rawData, string password) {}
-
- public X509Certificate (byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags) {}
-
- public X509Certificate (string fileName)
- {
- }
-
- public X509Certificate (string fileName, string password)
- {
- }
-
- public X509Certificate (string fileName, string password, X509KeyStorageFlags keyStorageFlags) {}
-
- public X509Certificate (SerializationInfo info, StreamingContext context) {}
-#endif
// public methods
- public virtual bool Equals (System.Security.Cryptography.X509Certificates.X509Certificate cert)
+ public virtual bool Equals (System.Security.Cryptography.X509Certificates.X509Certificate other)
{
- if (cert != null) {
- byte[] raw = cert.GetRawCertData ();
+ if (other == null) {
+ return false;
+ } else {
+ if (other.x509 == null) {
+ if (x509 == null)
+ return true;
+ throw new CryptographicException (Locale.GetText ("Certificate instance is empty."));
+ }
+
+ byte[] raw = other.x509.RawData;
if (raw != null) {
if (x509 == null)
return false;
return false;
}
}
- return (x509.RawData == null);
+ return ((x509 == null) || (x509.RawData == null));
}
// LAMESPEC: This is the equivalent of the "thumbprint" that can be seen
// algorithm used to sign the certificate).
public virtual byte[] GetCertHash ()
{
+ if (x509 == null)
+ throw new CryptographicException (Locale.GetText ("Certificate instance is empty."));
// we'll hash the cert only once and only if required
if ((cachedCertificateHash == null) && (x509 != null)) {
SHA1 sha = SHA1.Create ();
}
// strangly there are no DateTime returning function
- // 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
public virtual string GetEffectiveDateString ()
{
if (hideDates)
return null;
- DateTime dt = x509.ValidFrom.ToUniversalTime().AddHours (-8);
- return dt.ToString (); //"yyyy-MM-dd HH:mm:ss");
+ if (x509 == null)
+ throw new CryptographicException (Locale.GetText ("Certificate instance is empty."));
+
+ return x509.ValidFrom.ToLocalTime ().ToString ();
}
// strangly there are no DateTime returning function
- // 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
public virtual string GetExpirationDateString ()
{
if (hideDates)
return null;
- DateTime dt = x509.ValidUntil.ToUniversalTime().AddHours (-8);
- return dt.ToString (); //"yyyy-MM-dd HH:mm:ss");
+ if (x509 == null)
+ throw new CryptographicException (Locale.GetText ("Certificate instance is empty."));
+
+ return x509.ValidUntil.ToLocalTime ().ToString ();
}
// well maybe someday there'll be support for PGP or SPKI ?
public override int GetHashCode ()
{
+ if (x509 == null)
+ return 0;
// the cert hash may not be (yet) calculated
if (cachedCertificateHash == null)
GetCertHash();
else
return 0;
}
-
+
+ [Obsolete ("Use the Issuer property.")]
public virtual string GetIssuerName ()
{
+ if (x509 == null)
+ throw new CryptographicException (Locale.GetText ("Certificate instance is empty."));
return x509.IssuerName;
}
public virtual string GetKeyAlgorithm ()
{
+ if (x509 == null)
+ throw new CryptographicException (Locale.GetText ("Certificate instance is empty."));
return x509.KeyAlgorithm;
}
public virtual byte[] GetKeyAlgorithmParameters ()
{
- return x509.KeyAlgorithmParameters;
+ if (x509 == null)
+ throw new CryptographicException (Locale.GetText ("Certificate instance is empty."));
+
+ byte[] kap = x509.KeyAlgorithmParameters;
+ if (kap == null)
+ throw new CryptographicException (Locale.GetText ("Parameters not part of the certificate"));
+
+ return kap;
}
public virtual string GetKeyAlgorithmParametersString ()
{
- return tostr (x509.KeyAlgorithmParameters);
+ return tostr (GetKeyAlgorithmParameters ());
}
+ [Obsolete ("Use the Subject property.")]
public virtual string GetName ()
{
+ if (x509 == null)
+ throw new CryptographicException (Locale.GetText ("Certificate instance is empty."));
return x509.SubjectName;
}
public virtual byte[] GetPublicKey ()
{
+ if (x509 == null)
+ throw new CryptographicException (Locale.GetText ("Certificate instance is empty."));
return x509.PublicKey;
}
public virtual string GetPublicKeyString ()
{
- return tostr (x509.PublicKey);
+ return tostr (GetPublicKey ());
}
public virtual byte[] GetRawCertData ()
{
- return ((x509 != null) ? x509.RawData : null);
+ if (x509 == null)
+ throw new CryptographicException (Locale.GetText ("Certificate instance is empty."));
+ return x509.RawData;
}
public virtual string GetRawCertDataString ()
{
- return ((x509 != null) ? tostr (x509.RawData) : null);
+ if (x509 == null)
+ throw new CryptographicException (Locale.GetText ("Certificate instance is empty."));
+ return tostr (x509.RawData);
}
public virtual byte[] GetSerialNumber ()
{
+ if (x509 == null)
+ throw new CryptographicException (Locale.GetText ("Certificate instance is empty."));
return x509.SerialNumber;
}
public virtual string GetSerialNumberString ()
{
- return tostr (x509.SerialNumber);
+ byte[] sn = GetSerialNumber ();
+ Array.Reverse (sn);
+ return tostr (sn);
}
// to please corcompare ;-)
return base.ToString ();
}
- public virtual string ToString (bool details)
+ public virtual string ToString (bool fVerbose)
{
- if (details) {
- string nl = Environment.NewLine;
- StringBuilder sb = new StringBuilder ();
- 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);
- sb.Append (nl);
- return sb.ToString ();
- }
- else
+ if (!fVerbose || (x509 == null))
return base.ToString ();
- }
-#if !(NET_1_0 || NET_1_1)
- public virtual byte[] Export (X509ContentType contentType)
- {
- return null;
+ string nl = Environment.NewLine;
+ StringBuilder sb = new StringBuilder ();
+ 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 ());
+ sb.Append (nl);
+ return sb.ToString ();
}
- public virtual byte[] Export (X509ContentType contentType, string password)
+ private static byte[] Load (string fileName)
{
- return null;
- }
-
- void IDeserializationCallback.OnDeserialization (object sender) {}
-
- public virtual void Import (byte[] rawData) {}
-
- public virtual void Import (byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags) {}
-
- public virtual void Import (string fileName) {}
-
- public virtual void Import (string fileName, string password, X509KeyStorageFlags keyStorageFlags) {}
-
- void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context) {}
-
- public virtual void Reset() {}
-
- // properties
-
- public IntPtr Handle {
- get { return (IntPtr) 0; }
+ byte[] data = null;
+ using (FileStream fs = File.OpenRead (fileName)) {
+ data = new byte [fs.Length];
+ fs.Read (data, 0, data.Length);
+ fs.Close ();
+ }
+ return data;
}
-#endif
}
-}
\ No newline at end of file
+}