// 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;
// 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.
+ [Serializable]
#if NET_2_0
+ [ComVisible (true)]
public class X509Certificate : IDeserializationCallback, ISerializable {
#else
- [Serializable]
public class X509Certificate {
#endif
// typedef struct _CERT_CONTEXT {
public static X509Certificate CreateFromCertFile (string filename)
{
byte[] data = null;
- FileStream fs = new FileStream (filename, FileMode.Open);
- try {
+ using (FileStream fs = File.OpenRead (filename)) {
data = new byte [fs.Length];
fs.Read (data, 0, data.Length);
- }
- finally {
fs.Close ();
}
-
return new X509Certificate (data);
}
[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);
- }
- else {
+ 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);
+ throw new COMException (msg, e);
+ }
}
// constructors
}
}
- public X509Certificate (byte[] data) : this (data, true) {}
+ public X509Certificate (byte[] data) : this (data, true)
+ {
+ }
+ [SecurityPermission (SecurityAction.Demand, UnmanagedCode = 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) {
+ 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
}
public X509Certificate (System.Security.Cryptography.X509Certificates.X509Certificate cert)
{
+#if NET_2_0
+ if (cert == null)
+ throw new ArgumentNullException ();
+#endif
+
if (cert != null) {
byte[] data = cert.GetRawCertData ();
if (data != null)
}
#if NET_2_0
- public X509Certificate () {}
+ [MonoTODO]
+ public X509Certificate ()
+ {
+ }
+
+ [MonoTODO]
+ public X509Certificate (byte[] rawData, string password)
+ {
+ Import (rawData, password, X509KeyStorageFlags.DefaultKeySet);
+ }
- public X509Certificate (byte[] rawData, string password) {}
+ [MonoTODO]
+ public X509Certificate (byte[] rawData, SecureString password)
+ {
+ Import (rawData, password, X509KeyStorageFlags.DefaultKeySet);
+ }
- public X509Certificate (byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags) {}
+ [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);
}
- public X509Certificate (string fileName, string password, X509KeyStorageFlags keyStorageFlags) {}
+ [MonoTODO]
+ public X509Certificate (string fileName, SecureString password)
+ {
+ Import (fileName, password, X509KeyStorageFlags.DefaultKeySet);
+ }
- public X509Certificate (SerializationInfo info, StreamingContext context) {}
+ [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
return false;
}
}
- return (x509.RawData == null);
+ else
+ return false;
+ return x509 == null || (x509.RawData == null);
}
// LAMESPEC: This is the equivalent of the "thumbprint" that can be seen
}
// 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 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
}
// 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 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
}
// well maybe someday there'll be support for PGP or SPKI ?
else
return 0;
}
-
+
+#if NET_2_0
+ [Obsolete ("Use the Issuer property.")]
+#endif
public virtual string GetIssuerName ()
{
return x509.IssuerName;
return tostr (x509.KeyAlgorithmParameters);
}
+#if NET_2_0
+ [Obsolete ("Use the Subject property.")]
+#endif
public virtual string GetName ()
{
return x509.SubjectName;
}
#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 null;
+ return Export (contentType, (byte[])null);
}
+ [MonoTODO ("incomplete")]
+ [ComVisible (false)]
public virtual byte[] Export (X509ContentType contentType, string password)
{
- return null;
+ 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);
}
- void IDeserializationCallback.OnDeserialization (object sender) {}
+ [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);
+ }
+ }
+ }
- public virtual void Import (byte[] rawData) {}
+ [MonoTODO ("SecureString is incomplete")]
+ public virtual void Import (byte[] rawData, SecureString password, X509KeyStorageFlags keyStorageFlags)
+ {
+ Import (rawData, (string)null, keyStorageFlags);
+ }
- public virtual void Import (byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags) {}
+ [ComVisible (false)]
+ public virtual void Import (string fileName)
+ {
+ byte[] rawData = Load (fileName);
+ Import (rawData, (string)null, X509KeyStorageFlags.DefaultKeySet);
+ }
- public virtual void Import (string fileName) {}
+ [MonoTODO ("missing KeyStorageFlags support")]
+ [ComVisible (false)]
+ public virtual void Import (string fileName, string password, X509KeyStorageFlags keyStorageFlags)
+ {
+ byte[] rawData = Load (fileName);
+ Import (rawData, password, keyStorageFlags);
+ }
- public virtual void Import (string fileName, string password, X509KeyStorageFlags keyStorageFlags) {}
+ [MonoTODO ("SecureString is incomplete")]
+ public virtual void Import (string fileName, SecureString password, X509KeyStorageFlags keyStorageFlags)
+ {
+ byte[] rawData = Load (fileName);
+ Import (rawData, (string)null, keyStorageFlags);
+ }
- void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context) {}
+ 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;
+ }
+
+ [MonoTODO]
+ void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context)
+ {
+ }
- public virtual void Reset() {}
+ [MonoTODO]
+ [ComVisible (false)]
+ public virtual void Reset ()
+ {
+ }
// properties
+ [ComVisible (false)]
public IntPtr Handle {
get { return (IntPtr) 0; }
}