//
-// X509Certificates.cs: Handles X.509 certificates.
+// X509Certificate.cs: Handles X.509 certificates.
//
// Author:
// Sebastien Pouliot <sebastien@ximian.com>
using System.Text;
using Mono.Security;
-using Mono.Security.Authenticode;
using Mono.Security.X509;
-#if NET_2_0
using System.Runtime.Serialization;
-#endif
+using Mono.Security.Authenticode;
namespace System.Security.Cryptography.X509Certificates {
// and/or Authenticode certs. However this class works with older
// X509v1 certificates and non-authenticode (code signing) certs.
[Serializable]
-#if NET_2_0
- [ComVisible (true)]
- public class X509Certificate : IDeserializationCallback, ISerializable {
+#if NET_2_1
+ public partial class X509Certificate {
#else
- public class X509Certificate {
+ public partial class X509Certificate : IDeserializationCallback, ISerializable {
#endif
// typedef struct _CERT_CONTEXT {
// DWORD dwCertEncodingType;
public static X509Certificate CreateFromCertFile (string filename)
{
- byte[] data = null;
- using (FileStream fs = File.OpenRead (filename)) {
- data = new byte [fs.Length];
- fs.Read (data, 0, data.Length);
- fs.Close ();
- }
+ byte[] data = File.ReadAllBytes (filename);
return new X509Certificate (data);
}
-
+
[MonoTODO ("Incomplete - minimal validation in this version")]
public static X509Certificate CreateFromSignedFile (string filename)
{
try {
AuthenticodeDeformatter a = new AuthenticodeDeformatter (filename);
if (a.SigningCertificate != null) {
- if (a.Reason != 0) {
- string msg = String.Format (Locale.GetText (
- "Invalid digital signature on {0}, reason #{1}."),
- filename, a.Reason);
- throw new COMException (msg);
- }
return new X509Certificate (a.SigningCertificate.RawData);
}
-
- // if no signature is present return an empty certificate
- byte[] cert = null; // must not confuse compiler about null ;)
- return new X509Certificate (cert);
}
catch (SecurityException) {
// don't wrap SecurityException into a COMException
throw;
}
catch (Exception e) {
- string msg = String.Format (Locale.GetText ("Couldn't extract digital signature from {0}."), filename);
+ 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));
}
-
+
// 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;
}
}
{
}
- [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
public X509Certificate (IntPtr handle)
+ {
+ 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
+ }
+
+ [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);
}
-#if NET_2_0
- else
- throw new ArgumentException ("Invalid handle.");
-#endif
- // IntPtr.Zero results in an "empty" certificate instance
+ // for 1.x IntPtr.Zero results in an "empty" certificate instance
}
public X509Certificate (System.Security.Cryptography.X509Certificates.X509Certificate cert)
{
-#if NET_2_0
if (cert == null)
- throw new ArgumentNullException ();
-#endif
+ throw new ArgumentNullException ("cert");
if (cert != null) {
byte[] data = cert.GetRawCertData ();
}
}
-#if NET_2_0
- [MonoTODO]
- public X509Certificate ()
- {
- }
-
- [MonoTODO]
- public X509Certificate (byte[] rawData, string password)
- {
- Import (rawData, password, X509KeyStorageFlags.DefaultKeySet);
- }
-
- [MonoTODO]
- public X509Certificate (byte[] rawData, SecureString password)
- {
- Import (rawData, password, X509KeyStorageFlags.DefaultKeySet);
- }
-
- [MonoTODO]
- public X509Certificate (byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags)
- {
- Import (rawData, password, keyStorageFlags);
- }
-
- [MonoTODO]
- public X509Certificate (byte[] rawData, SecureString password, X509KeyStorageFlags keyStorageFlags)
- {
- Import (rawData, password, keyStorageFlags);
- }
-
- [MonoTODO]
- public X509Certificate (string fileName)
- {
- Import (fileName, (string)null, X509KeyStorageFlags.DefaultKeySet);
- }
-
- [MonoTODO]
- public X509Certificate (string fileName, string password)
- {
- Import (fileName, password, X509KeyStorageFlags.DefaultKeySet);
- }
-
- [MonoTODO]
- public X509Certificate (string fileName, SecureString password)
- {
- Import (fileName, password, X509KeyStorageFlags.DefaultKeySet);
- }
-
- [MonoTODO]
- public X509Certificate (string fileName, string password, X509KeyStorageFlags keyStorageFlags)
- {
- Import (fileName, password, keyStorageFlags);
- }
-
- [MonoTODO]
- public X509Certificate (string fileName, SecureString password, X509KeyStorageFlags keyStorageFlags)
- {
- Import (fileName, password, keyStorageFlags);
- }
-
- [MonoTODO]
- 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;
}
}
- else
- return false;
- return x509 == null || (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 ();
{
if (hideDates)
return null;
-#if NET_2_0
- return x509.ValidFrom.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
+ if (x509 == null)
+ throw new CryptographicException (Locale.GetText ("Certificate instance is empty."));
+
+ return x509.ValidFrom.ToLocalTime ().ToString ();
}
// strangly there are no DateTime returning function
{
if (hideDates)
return null;
-#if NET_2_0
- return x509.ValidUntil.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
+ 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();
return 0;
}
-#if NET_2_0
[Obsolete ("Use the Issuer property.")]
-#endif
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 ());
}
-#if NET_2_0
[Obsolete ("Use the Subject property.")]
-#endif
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_2_0
- public string Issuer {
- get { return x509.IssuerName; }
- }
-
- public string Subject {
- get { return x509.SubjectName; }
- }
-
- [ComVisible (false)]
- public override bool Equals (object obj)
- {
- X509Certificate x = (obj as X509Certificate);
- if (x != null)
- return this.Equals (x);
- return false;
- }
-
- [MonoTODO ("incomplete")]
- [ComVisible (false)]
- public virtual byte[] Export (X509ContentType contentType)
- {
- return Export (contentType, (byte[])null);
- }
-
- [MonoTODO ("incomplete")]
- [ComVisible (false)]
- public virtual byte[] Export (X509ContentType contentType, string password)
- {
- return Export (contentType, Encoding.UTF8.GetBytes (password));
- }
-
- [MonoTODO ("incomplete")]
- public virtual byte[] Export (X509ContentType contentType, SecureString password)
- {
- return Export (contentType, password.GetBuffer ());
- }
-
- [MonoTODO ("export!")]
- internal byte[] Export (X509ContentType contentType, byte[] password)
- {
- try {
- switch (contentType) {
- case X509ContentType.Cert:
- return x509.RawData;
- default:
- throw new NotSupportedException ();
- }
- }
- finally {
- // protect password
- if (password != null)
- Array.Clear (password, 0, password.Length);
- }
- }
-
- [MonoTODO]
- void IDeserializationCallback.OnDeserialization (object sender)
- {
- }
-
- [ComVisible (false)]
- public virtual void Import (byte[] rawData)
- {
- Import (rawData, (string)null, X509KeyStorageFlags.DefaultKeySet);
- }
-
- [MonoTODO ("missing KeyStorageFlags support")]
- [ComVisible (false)]
- public virtual void Import (byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags)
- {
- if (password == null) {
- x509 = new Mono.Security.X509.X509Certificate (rawData);
- // TODO - PKCS12 without password
- } else {
- // try PKCS#12
- try {
- PKCS12 pfx = new PKCS12 (rawData, password);
- if (pfx.Certificates.Count > 0) {
- x509 = pfx.Certificates [0];
- } else {
- x509 = null;
- }
- }
- catch {
- // it's possible to supply a (unrequired/unusued) password
- // fix bug #79028
- x509 = new Mono.Security.X509.X509Certificate (rawData);
- }
- }
- }
-
- [MonoTODO ("SecureString is incomplete")]
- public virtual void Import (byte[] rawData, SecureString password, X509KeyStorageFlags keyStorageFlags)
- {
- Import (rawData, (string)null, keyStorageFlags);
- }
-
- [ComVisible (false)]
- public virtual void Import (string fileName)
- {
- byte[] rawData = Load (fileName);
- Import (rawData, (string)null, X509KeyStorageFlags.DefaultKeySet);
- }
-
- [MonoTODO ("missing KeyStorageFlags support")]
- [ComVisible (false)]
- public virtual void Import (string fileName, string password, X509KeyStorageFlags keyStorageFlags)
- {
- byte[] rawData = Load (fileName);
- Import (rawData, password, keyStorageFlags);
- }
-
- [MonoTODO ("SecureString is incomplete")]
- public virtual void Import (string fileName, SecureString password, X509KeyStorageFlags keyStorageFlags)
- {
- byte[] rawData = Load (fileName);
- Import (rawData, (string)null, keyStorageFlags);
- }
- private byte[] Load (string fileName)
- {
- byte[] data = null;
- using (FileStream fs = new FileStream (fileName, FileMode.Open)) {
- data = new byte [fs.Length];
- fs.Read (data, 0, data.Length);
- fs.Close ();
- }
- return data;
+ 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 ();
}
- [MonoTODO]
- void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context)
+#if NET_4_0
+ protected static string FormatDate (DateTime date)
{
- }
-
- [MonoTODO]
- [ComVisible (false)]
- public virtual void Reset ()
- {
- }
-
- // properties
-
- [ComVisible (false)]
- public IntPtr Handle {
- get { return (IntPtr) 0; }
+ throw new NotImplementedException ();
}
#endif
}