diff --git a/external/api-snapshot b/external/api-snapshot index d6d62d84018b..7a7813863589 160000 --- a/external/api-snapshot +++ b/external/api-snapshot @@ -1 +1 @@ -Subproject commit d6d62d84018b1935566957495b68c88f801e6af4 +Subproject commit 7a7813863589464e22255c910ded2c1ed89189ab diff --git a/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509.cs b/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509.cs index abcdafbf0061..8560e4b77a11 100644 --- a/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509.cs +++ b/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509.cs @@ -87,7 +87,10 @@ public byte[] GetPublicKeyData () public byte[] GetSerialNumber (bool mono_style) { - return Instance.GetSerialNumber (mono_style); + var serial = Instance.GetSerialNumber (mono_style); + if (mono_style) + Array.Reverse (serial); + return serial; } public int GetVersion () diff --git a/mcs/class/System/Mono.AppleTls/MonoCertificatePal.cs b/mcs/class/System/Mono.AppleTls/MonoCertificatePal.cs index 27907fc00e13..765b1c44a1bf 100644 --- a/mcs/class/System/Mono.AppleTls/MonoCertificatePal.cs +++ b/mcs/class/System/Mono.AppleTls/MonoCertificatePal.cs @@ -57,7 +57,7 @@ public static SafeSecCertificateHandle FromOtherCertificate (X509CertificateImpl if (handle != IntPtr.Zero) return new SafeSecCertificateHandle (handle, false); - using (var data = CFData.FromData (impl.GetRawCertData ())) { + using (var data = CFData.FromData (impl.RawData)) { handle = SecCertificateCreateWithData (IntPtr.Zero, data.Handle); if (handle == IntPtr.Zero) throw new ArgumentException ("Not a valid DER-encoded X.509 certificate"); diff --git a/mcs/class/System/Mono.AppleTls/X509CertificateImplApple.cs b/mcs/class/System/Mono.AppleTls/X509CertificateImplApple.cs index fdcc0426e4c6..ec30415d538d 100644 --- a/mcs/class/System/Mono.AppleTls/X509CertificateImplApple.cs +++ b/mcs/class/System/Mono.AppleTls/X509CertificateImplApple.cs @@ -57,17 +57,18 @@ public override X509CertificateImpl Clone () [DllImport (CFHelpers.SecurityLibrary)] extern static IntPtr SecCertificateCopyData (IntPtr cert); - public override byte[] GetRawCertData () - { - ThrowIfContextInvalid (); - var data = SecCertificateCopyData (handle); - if (data == IntPtr.Zero) - throw new ArgumentException ("Not a valid certificate"); - - try { - return CFHelpers.FetchDataBuffer (data); - } finally { - CFHelpers.CFRelease (data); + public override byte[] RawData { + get { + ThrowIfContextInvalid (); + var data = SecCertificateCopyData (handle); + if (data == IntPtr.Zero) + throw new ArgumentException ("Not a valid certificate"); + + try { + return CFHelpers.FetchDataBuffer (data); + } finally { + CFHelpers.CFRelease (data); + } } } @@ -80,12 +81,13 @@ public string GetSubjectSummary () return ret; } - protected override byte[] GetCertHash (bool lazy) - { - // FIXME: might just return 'null' when 'lazy' is true. - ThrowIfContextInvalid (); - SHA1 sha = SHA1.Create (); - return sha.ComputeHash (GetRawCertData ()); + public override byte[] Thumbprint { + get { + // FIXME: might just return 'null' when 'lazy' is true. + ThrowIfContextInvalid (); + SHA1 sha = SHA1.Create (); + return sha.ComputeHash (RawData); + } } public override bool Equals (X509CertificateImpl other, out bool result) @@ -105,7 +107,7 @@ void MustFallback () ThrowIfContextInvalid (); if (fallback != null) return; - var mxCert = new MX.X509Certificate (GetRawCertData ()); + var mxCert = new MX.X509Certificate (RawData); fallback = new X509Certificate2ImplMono (mxCert); } @@ -116,45 +118,25 @@ public X509CertificateImpl FallbackImpl { } } - public override string GetSubjectName (bool legacyV1Mode) - { - return FallbackImpl.GetSubjectName (legacyV1Mode); - } + public override string Subject => FallbackImpl.Subject; - public override string GetIssuerName (bool legacyV1Mode) - { - return FallbackImpl.GetIssuerName (legacyV1Mode); - } + public override string Issuer => FallbackImpl.Issuer; - public override DateTime GetValidFrom () - { - return FallbackImpl.GetValidFrom (); - } + public override string LegacySubject => FallbackImpl.LegacySubject; - public override DateTime GetValidUntil () - { - return FallbackImpl.GetValidUntil (); - } + public override string LegacyIssuer => FallbackImpl.LegacyIssuer; - public override string GetKeyAlgorithm () - { - return FallbackImpl.GetKeyAlgorithm (); - } + public override DateTime NotAfter => FallbackImpl.NotAfter; - public override byte[] GetKeyAlgorithmParameters () - { - return FallbackImpl.GetKeyAlgorithmParameters (); - } + public override DateTime NotBefore => FallbackImpl.NotBefore; - public override byte[] GetPublicKey () - { - return FallbackImpl.GetPublicKey (); - } + public override string KeyAlgorithm => FallbackImpl.KeyAlgorithm; - public override byte[] GetSerialNumber () - { - return FallbackImpl.GetSerialNumber (); - } + public override byte[] KeyAlgorithmParameters => FallbackImpl.KeyAlgorithmParameters; + + public override byte[] PublicKeyValue => FallbackImpl.PublicKeyValue; + + public override byte[] SerialNumber => FallbackImpl.SerialNumber; public override byte[] Export (X509ContentType contentType, SafePasswordHandle password) { @@ -162,7 +144,7 @@ public override byte[] Export (X509ContentType contentType, SafePasswordHandle p switch (contentType) { case X509ContentType.Cert: - return GetRawCertData (); + return RawData; case X509ContentType.Pfx: // this includes Pkcs12 // TODO throw new NotSupportedException (); @@ -175,28 +157,6 @@ public override byte[] Export (X509ContentType contentType, SafePasswordHandle p } } - public override string ToString (bool full) - { - ThrowIfContextInvalid (); - - if (!full || fallback == null) { - var summary = GetSubjectSummary (); - return string.Format ("[X509Certificate: {0}]", summary); - } - - string nl = Environment.NewLine; - StringBuilder sb = new StringBuilder (); - sb.AppendFormat ("[Subject]{0} {1}{0}{0}", nl, GetSubjectName (false)); - - sb.AppendFormat ("[Issuer]{0} {1}{0}{0}", nl, GetIssuerName (false)); - sb.AppendFormat ("[Not Before]{0} {1}{0}{0}", nl, GetValidFrom ().ToLocalTime ()); - sb.AppendFormat ("[Not After]{0} {1}{0}{0}", nl, GetValidUntil ().ToLocalTime ()); - sb.AppendFormat ("[Thumbprint]{0} {1}{0}", nl, X509Helper.ToHexString (GetCertHash ())); - - sb.Append (nl); - return sb.ToString (); - } - protected override void Dispose (bool disposing) { if (handle != IntPtr.Zero){ diff --git a/mcs/class/System/Mono.Btls/X509CertificateImplBtls.cs b/mcs/class/System/Mono.Btls/X509CertificateImplBtls.cs index 423d3f88c032..0b170e2775f1 100644 --- a/mcs/class/System/Mono.Btls/X509CertificateImplBtls.cs +++ b/mcs/class/System/Mono.Btls/X509CertificateImplBtls.cs @@ -135,84 +135,32 @@ public override bool Equals (X509CertificateImpl other, out bool result) return true; } - protected override byte[] GetCertHash (bool lazy) - { - return X509.GetCertHash (); - } + public override byte[] Thumbprint => X509.GetCertHash (); - public override byte[] GetRawCertData () - { - return X509.GetRawData (MonoBtlsX509Format.DER); - } + public override byte[] RawData => X509.GetRawData (MonoBtlsX509Format.DER); - public override string GetSubjectName (bool legacyV1Mode) - { - if (legacyV1Mode) - return SubjectName.Decode (X500DistinguishedNameFlags.None); - return SubjectName.Name; - } + public override string Subject => SubjectName.Name; - public override string GetIssuerName (bool legacyV1Mode) - { - if (legacyV1Mode) - return IssuerName.Decode (X500DistinguishedNameFlags.None); - return IssuerName.Name; - } + public override string Issuer => IssuerName.Name; - public override DateTime GetValidFrom () - { - return X509.GetNotBefore ().ToLocalTime (); - } + public override string LegacySubject => SubjectName.Decode (X500DistinguishedNameFlags.None); - public override DateTime GetValidUntil () - { - return X509.GetNotAfter ().ToLocalTime (); - } + public override string LegacyIssuer => IssuerName.Decode (X500DistinguishedNameFlags.None); - public override byte[] GetPublicKey () - { - return X509.GetPublicKeyData (); - } + public override DateTime NotBefore => X509.GetNotBefore ().ToLocalTime (); - public override byte[] GetSerialNumber () - { - return X509.GetSerialNumber (true); - } + public override DateTime NotAfter => X509.GetNotAfter ().ToLocalTime (); - public override string GetKeyAlgorithm () - { - return PublicKey.Oid.Value; - } + public override byte[] PublicKeyValue => X509.GetPublicKeyData (); - public override byte[] GetKeyAlgorithmParameters () - { - return PublicKey.EncodedParameters.RawData; - } + public override byte[] SerialNumber => X509.GetSerialNumber (true); - internal override X509CertificateImplCollection IntermediateCertificates { - get { return intermediateCerts; } - } + public override string KeyAlgorithm => PublicKey.Oid.Value; - public override string ToString (bool full) - { - ThrowIfContextInvalid (); - - if (!full) { - var summary = GetSubjectName (false); - return string.Format ("[X509Certificate: {0}]", summary); - } - - string nl = Environment.NewLine; - StringBuilder sb = new StringBuilder (); - sb.AppendFormat ("[Subject]{0} {1}{0}{0}", nl, GetSubjectName (false)); + public override byte[] KeyAlgorithmParameters => PublicKey.EncodedParameters.RawData; - sb.AppendFormat ("[Issuer]{0} {1}{0}{0}", nl, GetIssuerName (false)); - sb.AppendFormat ("[Not Before]{0} {1}{0}{0}", nl, GetValidFrom ().ToLocalTime ()); - sb.AppendFormat ("[Not After]{0} {1}{0}{0}", nl, GetValidUntil ().ToLocalTime ()); - sb.AppendFormat ("[Thumbprint]{0} {1}{0}", nl, X509Helper.ToHexString (GetCertHash ())); - - sb.Append (nl); - return sb.ToString (); + internal override X509CertificateImplCollection IntermediateCertificates { + get { return intermediateCerts; } } protected override void Dispose (bool disposing) @@ -234,7 +182,7 @@ void MustFallback () if (fallback != null) return; fallback = SystemDependencyProvider.Instance.CertificateProvider.Import ( - GetRawCertData (), null, X509KeyStorageFlags.DefaultKeySet, + RawData, null, X509KeyStorageFlags.DefaultKeySet, CertificateImportFlags.DisableNativeBackend); } @@ -421,7 +369,7 @@ public override byte[] Export (X509ContentType contentType, SafePasswordHandle p switch (contentType) { case X509ContentType.Cert: - return GetRawCertData (); + return RawData; case X509ContentType.Pfx: // this includes Pkcs12 return ExportPkcs12 (password); case X509ContentType.SerializedCert: @@ -451,10 +399,10 @@ byte[] ExportPkcs12 (string password) attrs.Add (MX.PKCS9.localKeyId, localKeyId); if (password != null) pfx.Password = password; - pfx.AddCertificate (new MX.X509Certificate (GetRawCertData ()), attrs); + pfx.AddCertificate (new MX.X509Certificate (RawData), attrs); if (IntermediateCertificates != null) { for (int i = 0; i < IntermediateCertificates.Count; i++) - pfx.AddCertificate (new MX.X509Certificate (IntermediateCertificates [i].GetRawCertData ())); + pfx.AddCertificate (new MX.X509Certificate (IntermediateCertificates [i].RawData)); } var privateKey = PrivateKey; if (privateKey != null) diff --git a/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2.cs b/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2.cs index 358b28439ed1..f234f33b9278 100644 --- a/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2.cs +++ b/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2.cs @@ -148,11 +148,11 @@ public X509ExtensionCollection Extensions { public string FriendlyName { get { - ThrowIfContextInvalid (); + ThrowIfInvalid (); return friendlyName; } set { - ThrowIfContextInvalid (); + ThrowIfInvalid (); friendlyName = value; } } @@ -166,11 +166,11 @@ public X500DistinguishedName IssuerName { } public DateTime NotAfter { - get { return Impl.GetValidUntil ().ToLocalTime (); } + get { return Impl.NotAfter.ToLocalTime (); } } public DateTime NotBefore { - get { return Impl.GetValidFrom ().ToLocalTime (); } + get { return Impl.NotBefore.ToLocalTime (); } } public AsymmetricAlgorithm PrivateKey { diff --git a/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2ImplMono.cs b/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2ImplMono.cs index 35bfb2c297c4..de2e7d350cea 100644 --- a/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2ImplMono.cs +++ b/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2ImplMono.cs @@ -95,51 +95,38 @@ public override X509CertificateImpl Clone () return new X509Certificate2ImplMono (this); } + MX.X509Certificate Cert { + get { + ThrowIfContextInvalid (); + return _cert; + } + } + + #region Implemented X509CertificateImpl members - public override string GetIssuerName (bool legacyV1Mode) - { - ThrowIfContextInvalid (); - if (legacyV1Mode) - return _cert.IssuerName; - else - return MX.X501.ToString (_cert.GetIssuerName (), true, ", ", true); - } + public override string Issuer => MX.X501.ToString (Cert.GetIssuerName (), true, ", ", true); - public override string GetSubjectName (bool legacyV1Mode) - { - ThrowIfContextInvalid (); - if (legacyV1Mode) - return _cert.SubjectName; - else - return MX.X501.ToString (_cert.GetSubjectName (), true, ", ", true); - } + public override string Subject => MX.X501.ToString (Cert.GetSubjectName (), true, ", ", true); - public override byte[] GetRawCertData () - { - ThrowIfContextInvalid (); - return _cert.RawData; - } + public override string LegacyIssuer => Cert.IssuerName; - protected override byte[] GetCertHash (bool lazy) - { - ThrowIfContextInvalid (); - SHA1 sha = SHA1.Create (); - return sha.ComputeHash (_cert.RawData); - } + public override string LegacySubject => Cert.SubjectName; - public override DateTime GetValidFrom () - { - ThrowIfContextInvalid (); - return _cert.ValidFrom; - } + public override byte[] RawData => Cert.RawData; - public override DateTime GetValidUntil () - { - ThrowIfContextInvalid (); - return _cert.ValidUntil; + public override byte[] Thumbprint { + get { + ThrowIfContextInvalid (); + SHA1 sha = SHA1.Create (); + return sha.ComputeHash (_cert.RawData); + } } + public override DateTime NotBefore => Cert.ValidFrom.ToLocalTime (); + + public override DateTime NotAfter => Cert.ValidUntil.ToLocalTime (); + public override bool Equals (X509CertificateImpl other, out bool result) { // Use default implementation @@ -147,31 +134,22 @@ public override bool Equals (X509CertificateImpl other, out bool result) return false; } - public override string GetKeyAlgorithm () - { - ThrowIfContextInvalid (); - return _cert.KeyAlgorithm; - } + public override string KeyAlgorithm => Cert.KeyAlgorithm; - public override byte[] GetKeyAlgorithmParameters () - { - ThrowIfContextInvalid (); - return _cert.KeyAlgorithmParameters; - } + public override byte[] KeyAlgorithmParameters => Cert.KeyAlgorithmParameters ?? throw new CryptographicException (); - public override byte[] GetPublicKey () - { - ThrowIfContextInvalid (); - return _cert.PublicKey; - } + public override byte[] PublicKeyValue => Cert.PublicKey; - public override byte[] GetSerialNumber () - { - ThrowIfContextInvalid (); - return _cert.SerialNumber; + public override byte[] SerialNumber { + get { + ThrowIfContextInvalid (); + var serial = Cert.SerialNumber; + Array.Reverse (serial); + return serial; + } } - #endregion +#endregion // constructors @@ -553,71 +531,6 @@ public override void Reset () } } - public override string ToString () - { - if (_cert == null) - return "System.Security.Cryptography.X509Certificates.X509Certificate2"; - - return ToString (true); - } - - public override string ToString (bool verbose) - { - if (_cert == null) - return "System.Security.Cryptography.X509Certificates.X509Certificate2"; - - string nl = Environment.NewLine; - StringBuilder sb = new StringBuilder (); - - // the non-verbose X509Certificate2 == verbose X509Certificate - if (!verbose) { - sb.AppendFormat ("[Subject]{0} {1}{0}{0}", nl, GetSubjectName (false)); - sb.AppendFormat ("[Issuer]{0} {1}{0}{0}", nl, GetIssuerName (false)); - sb.AppendFormat ("[Not Before]{0} {1}{0}{0}", nl, GetValidFrom ().ToLocalTime ()); - sb.AppendFormat ("[Not After]{0} {1}{0}{0}", nl, GetValidUntil ().ToLocalTime ()); - sb.AppendFormat ("[Thumbprint]{0} {1}{0}", nl, X509Helper.ToHexString (GetCertHash ())); - sb.Append (nl); - return sb.ToString (); - } - - sb.AppendFormat ("[Version]{0} V{1}{0}{0}", nl, Version); - sb.AppendFormat ("[Subject]{0} {1}{0}{0}", nl, GetSubjectName (false)); - sb.AppendFormat ("[Issuer]{0} {1}{0}{0}", nl, GetIssuerName (false)); - sb.AppendFormat ("[Serial Number]{0} {1}{0}{0}", nl, GetSerialNumber ()); - sb.AppendFormat ("[Not Before]{0} {1}{0}{0}", nl, GetValidFrom ().ToLocalTime ()); - sb.AppendFormat ("[Not After]{0} {1}{0}{0}", nl, GetValidUntil ().ToLocalTime ()); - sb.AppendFormat ("[Thumbprint]{0} {1}{0}", nl, X509Helper.ToHexString (GetCertHash ())); - sb.AppendFormat ("[Signature Algorithm]{0} {1}({2}){0}{0}", nl, SignatureAlgorithm.FriendlyName, - SignatureAlgorithm.Value); - - AsymmetricAlgorithm key = PublicKey.Key; - sb.AppendFormat ("[Public Key]{0} Algorithm: ", nl); - if (key is RSA) - sb.Append ("RSA"); - else if (key is DSA) - sb.Append ("DSA"); - else - sb.Append (key.ToString ()); - sb.AppendFormat ("{0} Length: {1}{0} Key Blob: ", nl, key.KeySize); - AppendBuffer (sb, PublicKey.EncodedKeyValue.RawData); - sb.AppendFormat ("{0} Parameters: ", nl); - AppendBuffer (sb, PublicKey.EncodedParameters.RawData); - sb.Append (nl); - - return sb.ToString (); - } - - private static void AppendBuffer (StringBuilder sb, byte[] buffer) - { - if (buffer == null) - return; - for (int i=0; i < buffer.Length; i++) { - sb.Append (buffer [i].ToString ("x2")); - if (i < buffer.Length - 1) - sb.Append (" "); - } - } - [MonoTODO ("by default this depends on the incomplete X509Chain")] public override bool Verify (X509Certificate2 thisCertificate) { @@ -708,4 +621,3 @@ internal override X509Certificate2Impl FallbackImpl { } } } - diff --git a/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Helper2.cs b/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Helper2.cs index 5881a2af1501..7e7ecbb393dd 100644 --- a/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Helper2.cs +++ b/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Helper2.cs @@ -126,7 +126,7 @@ static MonoBtlsX509 GetNativeInstance (X509CertificateImpl impl) if (btlsImpl != null) return btlsImpl.X509.Copy (); else - return MonoBtlsX509.LoadFromData (impl.GetRawCertData (), MonoBtlsX509Format.DER); + return MonoBtlsX509.LoadFromData (impl.RawData, MonoBtlsX509Format.DER); } #endif } diff --git a/mcs/class/System/Test/System.Security.Cryptography.X509Certificates/X509Cert20Test.cs b/mcs/class/System/Test/System.Security.Cryptography.X509Certificates/X509Cert20Test.cs index 869154d63069..5a5ba53c8b39 100644 --- a/mcs/class/System/Test/System.Security.Cryptography.X509Certificates/X509Cert20Test.cs +++ b/mcs/class/System/Test/System.Security.Cryptography.X509Certificates/X509Cert20Test.cs @@ -454,8 +454,9 @@ public void Empty_GetSerialNumberString () new X509Certificate ().GetSerialNumberString (); } +#if !MOBILE [Test] - [ExpectedException (typeof (NullReferenceException))] + [ExpectedException (typeof (PlatformNotSupportedException))] public void GetObjectData_Null () { X509Certificate x = new X509Certificate (); @@ -464,6 +465,7 @@ public void GetObjectData_Null () } [Test] + [ExpectedException (typeof (PlatformNotSupportedException))] public void GetObjectData () { X509Certificate x = new X509Certificate (cert1); @@ -471,26 +473,22 @@ public void GetObjectData () Assert.IsNotNull (s, "ISerializable"); SerializationInfo info = new SerializationInfo (typeof (X509Certificate), new FormatterConverter ()); s.GetObjectData (info, new StreamingContext (StreamingContextStates.All)); - Assert.AreEqual (1, info.MemberCount, "MemberCount"); - byte[] raw = (byte[]) info.GetValue ("RawData", typeof (byte[])); } +#endif [Test] - [ExpectedException (typeof (NullReferenceException))] + [ExpectedException (typeof (PlatformNotSupportedException))] public void Ctor_Serialization_Null () { new X509Certificate (null, new StreamingContext (StreamingContextStates.All)); } [Test] + [ExpectedException (typeof (PlatformNotSupportedException))] public void Ctor_Serialization () { SerializationInfo info = new SerializationInfo (typeof (X509Certificate), new FormatterConverter ()); - info.AddValue ("RawData", cert1); - X509Certificate x = new X509Certificate (info, new StreamingContext (StreamingContextStates.All)); - Assert.AreEqual (cert1, x.GetRawCertData (), "GetRawCertData"); - // decoding is done too - Assert.AreEqual ("02720006E8", x.GetSerialNumberString (), "SerialNumber"); + new X509Certificate (info, new StreamingContext (StreamingContextStates.All)); } diff --git a/mcs/class/corlib/System.Security.Cryptography.X509Certificates/X509Certificate.cs b/mcs/class/corlib/System.Security.Cryptography.X509Certificates/X509Certificate.cs index 5d155df17a01..d447224c096b 100644 --- a/mcs/class/corlib/System.Security.Cryptography.X509Certificates/X509Certificate.cs +++ b/mcs/class/corlib/System.Security.Cryptography.X509Certificates/X509Certificate.cs @@ -28,275 +28,674 @@ // using System.IO; +using System.Globalization; using System.Runtime.InteropServices; +using System.Runtime.Serialization; using System.Security.Permissions; +using System.Diagnostics; using System.Text; +using Internal.Cryptography; +using Microsoft.Win32.SafeHandles; using Mono.Security; - -using System.Runtime.Serialization; using Mono.Security.Authenticode; -namespace System.Security.Cryptography.X509Certificates { - +namespace System.Security.Cryptography.X509Certificates +{ // References: // a. Internet X.509 Public Key Infrastructure Certificate and CRL Profile // http://www.ietf.org/rfc/rfc3280.txt - + // 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 MOBILE - public partial class X509Certificate { -#else - public partial class X509Certificate : IDeserializationCallback, ISerializable { -#endif + public partial class X509Certificate : IDisposable, IDeserializationCallback, ISerializable + { +#region CoreFX Implementation + X509CertificateImpl impl; + volatile byte[] lazyCertHash; + volatile byte[] lazySerialNumber; + volatile string lazyIssuer; + volatile string lazySubject; + volatile string lazyKeyAlgorithm; + volatile byte[] lazyKeyAlgorithmParameters; + volatile byte[] lazyPublicKey; + DateTime lazyNotBefore = DateTime.MinValue; + DateTime lazyNotAfter = DateTime.MinValue; - private bool hideDates; - - // static methods - - public static X509Certificate CreateFromCertFile (string filename) + public virtual void Reset () { - byte[] data = File.ReadAllBytes (filename); - return new X509Certificate (data); + if (impl != null) { + impl.Dispose (); + impl = null; + } + + lazyCertHash = null; + lazyIssuer = null; + lazySubject = null; + lazySerialNumber = null; + lazyKeyAlgorithm = null; + lazyKeyAlgorithmParameters = null; + lazyPublicKey = null; + lazyNotBefore = DateTime.MinValue; + lazyNotAfter = DateTime.MinValue; } - [MonoTODO ("Incomplete - minimal validation in this version")] - public static X509Certificate CreateFromSignedFile (string filename) +#endregion + +#region CoreFX Implementation - with X509Helper + + public X509Certificate () { - 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; - } - 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)); } - // constructors - - // special constructor for Publisher (and related classes). - // Dates strings are null - internal X509Certificate (byte[] data, bool dates) + public X509Certificate (byte[] data) { - if (data != null) { - Import (data, (string)null, X509KeyStorageFlags.DefaultKeySet); - hideDates = !dates; + if (data != null && data.Length != 0) { + // For compat reasons, this constructor treats passing a null or empty data set as the same as calling the nullary constructor. + using (var safePasswordHandle = new SafePasswordHandle ((string)null)) + impl = X509Helper.Import (data, safePasswordHandle, X509KeyStorageFlags.DefaultKeySet); } } - - public X509Certificate (byte[] data) : this (data, true) + + public X509Certificate (byte[] rawData, string password) + : this (rawData, password, X509KeyStorageFlags.DefaultKeySet) + { + } + + [CLSCompliantAttribute (false)] + public X509Certificate (byte[] rawData, SecureString password) + : this (rawData, password, X509KeyStorageFlags.DefaultKeySet) { } - public X509Certificate (IntPtr handle) + public X509Certificate (byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags) { - if (handle == IntPtr.Zero) - throw new ArgumentException ("Invalid handle."); + if (rawData == null || rawData.Length == 0) + throw new ArgumentException (SR.Arg_EmptyOrNullArray, nameof (rawData)); + ValidateKeyStorageFlags (keyStorageFlags); + + using (var safePasswordHandle = new SafePasswordHandle (password)) + impl = X509Helper.Import (rawData, safePasswordHandle, keyStorageFlags); + } + + [CLSCompliantAttribute (false)] + public X509Certificate (byte[] rawData, SecureString password, X509KeyStorageFlags keyStorageFlags) + { + if (rawData == null || rawData.Length == 0) + throw new ArgumentException (SR.Arg_EmptyOrNullArray, nameof (rawData)); + + ValidateKeyStorageFlags (keyStorageFlags); + + using (var safePasswordHandle = new SafePasswordHandle (password)) + impl = X509Helper.Import (rawData, safePasswordHandle, keyStorageFlags); + } + + public X509Certificate (IntPtr handle) + { throw new PlatformNotSupportedException ("Initializing `X509Certificate` from native handle is not supported."); } internal X509Certificate (X509CertificateImpl impl) { + Debug.Assert (impl != null); this.impl = X509Helper.InitFromCertificate (impl); } - public X509Certificate (X509Certificate cert) + public X509Certificate (string fileName) + : this (fileName, (string)null, X509KeyStorageFlags.DefaultKeySet) + { + } + + public X509Certificate (string fileName, string password) + : this (fileName, password, X509KeyStorageFlags.DefaultKeySet) + { + } + + [CLSCompliantAttribute(false)] + public X509Certificate (string fileName, SecureString password) + : this (fileName, password, X509KeyStorageFlags.DefaultKeySet) + { + } + + public X509Certificate (string fileName, string password, X509KeyStorageFlags keyStorageFlags) + { + if (fileName == null) + throw new ArgumentNullException (nameof (fileName)); + + ValidateKeyStorageFlags (keyStorageFlags); + + var rawData = File.ReadAllBytes (fileName); + using (var safePasswordHandle = new SafePasswordHandle (password)) + impl = X509Helper.Import (rawData, safePasswordHandle, keyStorageFlags); + } + + [CLSCompliantAttribute (false)] + public X509Certificate (string fileName, SecureString password, X509KeyStorageFlags keyStorageFlags) : this () + { + if (fileName == null) + throw new ArgumentNullException (nameof (fileName)); + + ValidateKeyStorageFlags (keyStorageFlags); + + var rawData = File.ReadAllBytes (fileName); + using (var safePasswordHandle = new SafePasswordHandle (password)) + impl = X509Helper.Import (rawData, safePasswordHandle, keyStorageFlags); + } + + public X509Certificate (X509Certificate cert) { if (cert == null) - throw new ArgumentNullException ("cert"); + throw new ArgumentNullException (nameof (cert)); impl = X509Helper.InitFromCertificate (cert); } - internal void ImportHandle (X509CertificateImpl impl) +#endregion + +#region CoreFX Implementation + + [System.Diagnostics.CodeAnalysis.SuppressMessage ("Microsoft.Usage", "CA2229", Justification = "Public API has already shipped.")] + public X509Certificate (SerializationInfo info, StreamingContext context) : this () { - Reset (); - this.impl = impl; + throw new PlatformNotSupportedException (); } - internal X509CertificateImpl Impl { + public static X509Certificate CreateFromCertFile (string filename) + { + return new X509Certificate (filename); + } + + public static X509Certificate CreateFromSignedFile (string filename) + { + return new X509Certificate (filename); + } + + void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context) + { + throw new PlatformNotSupportedException (); + } + + void IDeserializationCallback.OnDeserialization (object sender) + { + throw new PlatformNotSupportedException (); + } + + public IntPtr Handle { get { - return impl; + if (X509Helper.IsValid (impl)) + return impl.Handle; + return IntPtr.Zero; } } - internal bool IsValid { - get { return X509Helper.IsValid (impl); } + public string Issuer { + get { + ThrowIfInvalid (); + + string issuer = lazyIssuer; + if (issuer == null) + issuer = lazyIssuer = Impl.Issuer; + return issuer; + } + } + + public string Subject { + get { + ThrowIfInvalid (); + + string subject = lazySubject; + if (subject == null) + subject = lazySubject = Impl.Subject; + return subject; + } } - internal void ThrowIfContextInvalid () + public void Dispose () { - X509Helper.ThrowIfContextInvalid (impl); + Dispose (true); } - // public methods - - public virtual bool Equals (System.Security.Cryptography.X509Certificates.X509Certificate other) + protected virtual void Dispose (bool disposing) { - if (other == null) { + if (disposing) + Reset (); + } + + public override bool Equals (object obj) + { + X509Certificate other = obj as X509Certificate; + if (other == null) + return false; + return Equals (other); + } + + public virtual bool Equals (X509Certificate other) + { + if (other == null) + return false; + + if (Impl == null) + return other.Impl == null; + + if (!Issuer.Equals (other.Issuer)) return false; - } else { - if (!X509Helper.IsValid (other.impl)) { - if (!X509Helper.IsValid (impl)) - return true; - throw new CryptographicException (Locale.GetText ("Certificate instance is empty.")); - } - return X509CertificateImpl.Equals (impl, other.impl); + byte[] thisSerialNumber = GetRawSerialNumber (); + byte[] otherSerialNumber = other.GetRawSerialNumber (); + + if (thisSerialNumber.Length != otherSerialNumber.Length) + return false; + for (int i = 0; i < thisSerialNumber.Length; i++) { + if (thisSerialNumber[i] != otherSerialNumber[i]) + return false; } + + return true; } - // 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 () +#endregion + +#region CoreFX Implementation - With X509Helper + + public virtual byte[] Export (X509ContentType contentType) { - X509Helper.ThrowIfContextInvalid (impl); - return impl.GetCertHash (); + return Export (contentType, (string)null); } - - public virtual string GetCertHashString () + + public virtual byte[] Export (X509ContentType contentType, string password) { - // must call GetCertHash (not variable) or optimization wont work - return X509Helper.ToHexString (GetCertHash ()); + VerifyContentType (contentType); + + if (Impl == null) + throw new CryptographicException (ErrorCode.E_POINTER); // Not the greatest error, but needed for backward compat. + + using (var safePasswordHandle = new SafePasswordHandle (password)) + return Impl.Export (contentType, safePasswordHandle); } - - // strangly there are no DateTime returning function + + [System.CLSCompliantAttribute (false)] + public virtual byte[] Export (X509ContentType contentType, SecureString password) + { + VerifyContentType (contentType); + + if (Impl == null) + throw new CryptographicException (ErrorCode.E_POINTER); // Not the greatest error, but needed for backward compat. + + using (var safePasswordHandle = new SafePasswordHandle (password)) + return Impl.Export (contentType, safePasswordHandle); + } + +#endregion + +#region CoreFX Implementation + + public virtual string GetRawCertDataString () + { + ThrowIfInvalid (); + return GetRawCertData ().ToHexStringUpper (); + } + + public virtual byte[] GetCertHash () + { + ThrowIfInvalid (); + return GetRawCertHash ().CloneByteArray (); + } + + public virtual byte[] GetCertHash (HashAlgorithmName hashAlgorithm) + { + throw new PlatformNotSupportedException (); + } + + public virtual bool TryGetCertHash (HashAlgorithmName hashAlgorithm, Span destination, out int bytesWritten) + { + throw new PlatformNotSupportedException (); + } + + public virtual string GetCertHashString () + { + ThrowIfInvalid (); + return GetRawCertHash ().ToHexStringUpper (); + } + + public virtual string GetCertHashString (HashAlgorithmName hashAlgorithm) + { + ThrowIfInvalid (); + + return GetCertHash (hashAlgorithm).ToHexStringUpper (); + } + + // Only use for internal purposes when the returned byte[] will not be mutated + byte[] GetRawCertHash () + { + return lazyCertHash ?? (lazyCertHash = Impl.Thumbprint); + } + public virtual string GetEffectiveDateString () { - if (hideDates) - return null; - X509Helper.ThrowIfContextInvalid (impl); + return GetNotBefore ().ToString (); + } - return impl.GetValidFrom ().ToLocalTime ().ToString (); + public virtual string GetExpirationDateString () + { + return GetNotAfter ().ToString (); } - - // strangly there are no DateTime returning function - public virtual string GetExpirationDateString () + + public virtual string GetFormat () { - if (hideDates) - return null; - X509Helper.ThrowIfContextInvalid (impl); + return "X509"; + } - return impl.GetValidUntil ().ToLocalTime ().ToString (); + public virtual string GetPublicKeyString () + { + return GetPublicKey ().ToHexStringUpper (); } - - // well maybe someday there'll be support for PGP or SPKI ? - public virtual string GetFormat () + + public virtual byte[] GetRawCertData () { - return "X509"; // DO NOT TRANSLATE + ThrowIfInvalid (); + + return Impl.RawData.CloneByteArray (); } - + public override int GetHashCode () { - if (!X509Helper.IsValid (impl)) + if (Impl == null) return 0; - return impl.GetHashCode (); + + byte[] thumbPrint = GetRawCertHash (); + int value = 0; + for (int i = 0; i < thumbPrint.Length && i < 4; ++i) { + value = value << 8 | thumbPrint[i]; + } + return value; } - [Obsolete ("Use the Issuer property.")] - public virtual string GetIssuerName () + public virtual string GetKeyAlgorithm () { - X509Helper.ThrowIfContextInvalid (impl); - return impl.GetIssuerName (true); + ThrowIfInvalid (); + + string keyAlgorithm = lazyKeyAlgorithm; + if (keyAlgorithm == null) + keyAlgorithm = lazyKeyAlgorithm = Impl.KeyAlgorithm; + return keyAlgorithm; } - - public virtual string GetKeyAlgorithm () + + public virtual byte[] GetKeyAlgorithmParameters () { - X509Helper.ThrowIfContextInvalid (impl); - return impl.GetKeyAlgorithm (); + ThrowIfInvalid (); + + byte[] keyAlgorithmParameters = lazyKeyAlgorithmParameters; + if (keyAlgorithmParameters == null) + keyAlgorithmParameters = lazyKeyAlgorithmParameters = Impl.KeyAlgorithmParameters; + return keyAlgorithmParameters.CloneByteArray (); } - - public virtual byte[] GetKeyAlgorithmParameters () + + public virtual string GetKeyAlgorithmParametersString () { - X509Helper.ThrowIfContextInvalid (impl); + ThrowIfInvalid (); - byte[] kap = impl.GetKeyAlgorithmParameters (); - if (kap == null) - throw new CryptographicException (Locale.GetText ("Parameters not part of the certificate")); + byte[] keyAlgorithmParameters = GetKeyAlgorithmParameters (); + return keyAlgorithmParameters.ToHexStringUpper (); + } - return kap; + public virtual byte[] GetPublicKey () + { + ThrowIfInvalid (); + + byte[] publicKey = lazyPublicKey; + if (publicKey == null) + publicKey = lazyPublicKey = Impl.PublicKeyValue; + return publicKey.CloneByteArray (); + } + + public virtual byte[] GetSerialNumber () + { + ThrowIfInvalid (); + byte[] serialNumber = GetRawSerialNumber ().CloneByteArray (); + // PAL always returns big-endian, GetSerialNumber returns little-endian + Array.Reverse (serialNumber); + return serialNumber; } - - public virtual string GetKeyAlgorithmParametersString () + + public virtual string GetSerialNumberString () { - return X509Helper.ToHexString (GetKeyAlgorithmParameters ()); + ThrowIfInvalid (); + // PAL always returns big-endian, GetSerialNumberString returns big-endian too + return GetRawSerialNumber ().ToHexStringUpper (); } - - [Obsolete ("Use the Subject property.")] + + // Only use for internal purposes when the returned byte[] will not be mutated + byte[] GetRawSerialNumber () + { + return lazySerialNumber ?? (lazySerialNumber = Impl.SerialNumber); + } + + // See https://github.com/dotnet/corefx/issues/30544 + [Obsolete ("This method has been deprecated. Please use the Subject property instead. http://go.microsoft.com/fwlink/?linkid=14202")] public virtual string GetName () { - X509Helper.ThrowIfContextInvalid (impl); - return impl.GetSubjectName (true); + ThrowIfInvalid (); + return Impl.LegacySubject; } - - public virtual byte[] GetPublicKey () + + // See https://github.com/dotnet/corefx/issues/30544 + [Obsolete ("This method has been deprecated. Please use the Issuer property instead. http://go.microsoft.com/fwlink/?linkid=14202")] + public virtual string GetIssuerName () { - X509Helper.ThrowIfContextInvalid (impl); - return impl.GetPublicKey (); + ThrowIfInvalid (); + return Impl.LegacyIssuer; } - - public virtual string GetPublicKeyString () + + public override string ToString () { - return X509Helper.ToHexString (GetPublicKey ()); + return ToString (fVerbose: false); } - - public virtual byte[] GetRawCertData () + + public virtual string ToString (bool fVerbose) { - X509Helper.ThrowIfContextInvalid (impl); - return impl.GetRawCertData (); + if (!fVerbose || !X509Helper.IsValid (impl)) + return base.ToString (); + + StringBuilder sb = new StringBuilder (); + + // Subject + sb.AppendLine ("[Subject]"); + sb.Append (" "); + sb.AppendLine (Subject); + + // Issuer + sb.AppendLine (); + sb.AppendLine ("[Issuer]"); + sb.Append (" "); + sb.AppendLine (Issuer); + + // Serial Number + sb.AppendLine (); + sb.AppendLine ("[Serial Number]"); + sb.Append (" "); + byte[] serialNumber = GetSerialNumber (); + Array.Reverse (serialNumber); + sb.Append (serialNumber.ToHexArrayUpper ()); + sb.AppendLine (); + + // NotBefore + sb.AppendLine (); + sb.AppendLine ("[Not Before]"); + sb.Append (" "); + sb.AppendLine (FormatDate (GetNotBefore ())); + + // NotAfter + sb.AppendLine (); + sb.AppendLine ("[Not After]"); + sb.Append (" "); + sb.AppendLine (FormatDate (GetNotAfter ())); + + // Thumbprint + sb.AppendLine (); + sb.AppendLine ("[Thumbprint]"); + sb.Append (" "); + sb.Append (GetRawCertHash ().ToHexArrayUpper ()); + sb.AppendLine (); + + return sb.ToString (); } - - public virtual string GetRawCertDataString () + +#endregion + +#region Mono Implementation + + /* + /* CoreFX throws + /* throw new PlatformNotSupportedException(SR.NotSupported_ImmutableX509Certificate); + /* everywhere. + */ + + [ComVisible (false)] + public virtual void Import (byte[] rawData) { - X509Helper.ThrowIfContextInvalid (impl); - return X509Helper.ToHexString (impl.GetRawCertData ()); + Import (rawData, (string)null, X509KeyStorageFlags.DefaultKeySet); } - - public virtual byte[] GetSerialNumber () + + [ComVisible (false)] + public virtual void Import (byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags) { - X509Helper.ThrowIfContextInvalid (impl); - return impl.GetSerialNumber (); + Reset (); + using (var safePasswordHandle = new SafePasswordHandle (password)) + impl = X509Helper.Import (rawData, safePasswordHandle, keyStorageFlags); } - - public virtual string GetSerialNumberString () + + public virtual void Import (byte[] rawData, SecureString password, X509KeyStorageFlags keyStorageFlags) { - byte[] sn = GetSerialNumber (); - Array.Reverse (sn); - return X509Helper.ToHexString (sn); + using (var safePasswordHandle = new SafePasswordHandle (password)) + impl = X509Helper.Import (rawData, safePasswordHandle, keyStorageFlags); } - - // to please corcompare ;-) - public override string ToString () + + [ComVisible (false)] + public virtual void Import (string fileName) { - return base.ToString (); + Import (fileName, (string)null, X509KeyStorageFlags.DefaultKeySet); } - - public virtual string ToString (bool fVerbose) + + [ComVisible (false)] + public virtual void Import (string fileName, string password, X509KeyStorageFlags keyStorageFlags) { - if (!fVerbose || !X509Helper.IsValid (impl)) - return base.ToString (); + byte[] rawData = File.ReadAllBytes (fileName); + using (var safePasswordHandle = new SafePasswordHandle (password)) + impl = X509Helper.Import (rawData, safePasswordHandle, keyStorageFlags); + } - return impl.ToString (true); + public virtual void Import (string fileName, SecureString password, X509KeyStorageFlags keyStorageFlags) + { + byte[] rawData = File.ReadAllBytes (fileName); + using (var safePasswordHandle = new SafePasswordHandle (password)) + impl = X509Helper.Import (rawData, safePasswordHandle, keyStorageFlags); } +#endregion + +#region CoreFX Implementation + + internal DateTime GetNotAfter () + { + ThrowIfInvalid (); + + DateTime notAfter = lazyNotAfter; + if (notAfter == DateTime.MinValue) + notAfter = lazyNotAfter = impl.NotAfter; + return notAfter; + } + + internal DateTime GetNotBefore () + { + ThrowIfInvalid (); + + DateTime notBefore = lazyNotBefore; + if (notBefore == DateTime.MinValue) + notBefore = lazyNotBefore = impl.NotBefore; + return notBefore; + } + + /// + /// Convert a date to a string. + /// + /// Some cultures, specifically using the Um-AlQura calendar cannot convert dates far into + /// the future into strings. If the expiration date of an X.509 certificate is beyond the range + /// of one of these cases, we need to fall back to a calendar which can express the dates + /// protected static string FormatDate (DateTime date) { - throw new NotImplementedException (); + CultureInfo culture = CultureInfo.CurrentCulture; + + if (!culture.DateTimeFormat.Calendar.IsValidDay (date.Year, date.Month, date.Day, 0)) { + // The most common case of culture failing to work is in the Um-AlQuara calendar. In this case, + // we can fall back to the Hijri calendar, otherwise fall back to the invariant culture. + if (culture.DateTimeFormat.Calendar is UmAlQuraCalendar) { + culture = culture.Clone () as CultureInfo; + culture.DateTimeFormat.Calendar = new HijriCalendar (); + } else { + culture = CultureInfo.InvariantCulture; + } + } + + return date.ToString (culture); + } + + internal static void ValidateKeyStorageFlags (X509KeyStorageFlags keyStorageFlags) + { + if ((keyStorageFlags & ~KeyStorageFlagsAll) != 0) + throw new ArgumentException (SR.Argument_InvalidFlag, nameof (keyStorageFlags)); + + const X509KeyStorageFlags EphemeralPersist = + X509KeyStorageFlags.EphemeralKeySet | X509KeyStorageFlags.PersistKeySet; + + X509KeyStorageFlags persistenceFlags = keyStorageFlags & EphemeralPersist; + + if (persistenceFlags == EphemeralPersist) { + throw new ArgumentException ( + SR.Format (SR.Cryptography_X509_InvalidFlagCombination, persistenceFlags), + nameof (keyStorageFlags)); + } + } + + void VerifyContentType (X509ContentType contentType) + { + if (!(contentType == X509ContentType.Cert || contentType == X509ContentType.SerializedCert || contentType == X509ContentType.Pkcs12)) + throw new CryptographicException (SR.Cryptography_X509_InvalidContentType); + } + + internal const X509KeyStorageFlags KeyStorageFlagsAll = + X509KeyStorageFlags.UserKeySet | + X509KeyStorageFlags.MachineKeySet | + X509KeyStorageFlags.Exportable | + X509KeyStorageFlags.UserProtected | + X509KeyStorageFlags.PersistKeySet | + X509KeyStorageFlags.EphemeralKeySet; + +#endregion // CoreFX Implementation + + internal void ImportHandle (X509CertificateImpl impl) + { + Reset (); + this.impl = impl; + } + + internal X509CertificateImpl Impl { + get { + return impl; + } + } + + internal bool IsValid { + get { return X509Helper.IsValid (impl); } + } + + internal void ThrowIfInvalid () + { + X509Helper.ThrowIfContextInvalid (impl); } } } diff --git a/mcs/class/corlib/System.Security.Cryptography.X509Certificates/X509Certificate20.cs b/mcs/class/corlib/System.Security.Cryptography.X509Certificates/X509Certificate20.cs deleted file mode 100644 index f1f0f2de9ac5..000000000000 --- a/mcs/class/corlib/System.Security.Cryptography.X509Certificates/X509Certificate20.cs +++ /dev/null @@ -1,257 +0,0 @@ -// -// X509Certificate20.cs: Partial class to handle new 2.0-only stuff -// -// Author: -// Sebastien Pouliot -// -// (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com) -// Copyright (C) 2004-2006,2008 Novell, Inc (http://www.novell.com) -// Copyright 2013 Xamarin Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -using System.IO; -using System.Text; -using System.Runtime.InteropServices; -using System.Security.Permissions; -using Microsoft.Win32.SafeHandles; - -using Mono.Security; - -using System.Runtime.Serialization; - -namespace System.Security.Cryptography.X509Certificates { - - [ComVisible (true)] - [MonoTODO ("X509ContentType.SerializedCert isn't supported (anywhere in the class)")] - public partial class X509Certificate : IDeserializationCallback, ISerializable, IDisposable { - private string issuer_name; - private string subject_name; - - - public X509Certificate () - { - // this allows an empty certificate to exists - } - - public X509Certificate (byte[] rawData, string password) - { - Import (rawData, password, X509KeyStorageFlags.DefaultKeySet); - } - - [MonoTODO ("SecureString support is incomplete")] - public X509Certificate (byte[] rawData, SecureString password) - { - Import (rawData, password, X509KeyStorageFlags.DefaultKeySet); - } - - public X509Certificate (byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags) - { - Import (rawData, password, keyStorageFlags); - } - - [MonoTODO ("SecureString support is incomplete")] - public X509Certificate (byte[] rawData, SecureString password, X509KeyStorageFlags keyStorageFlags) - { - Import (rawData, password, keyStorageFlags); - } - - public X509Certificate (string fileName) - { - Import (fileName, (string)null, X509KeyStorageFlags.DefaultKeySet); - } - - public X509Certificate (string fileName, string password) - { - Import (fileName, password, X509KeyStorageFlags.DefaultKeySet); - } - - [MonoTODO ("SecureString support is incomplete")] - public X509Certificate (string fileName, SecureString password) - { - Import (fileName, password, X509KeyStorageFlags.DefaultKeySet); - } - - public X509Certificate (string fileName, string password, X509KeyStorageFlags keyStorageFlags) - { - Import (fileName, password, keyStorageFlags); - } - - [MonoTODO ("SecureString support is incomplete")] - public X509Certificate (string fileName, SecureString password, X509KeyStorageFlags keyStorageFlags) - { - Import (fileName, password, keyStorageFlags); - } - - public X509Certificate (SerializationInfo info, StreamingContext context) - { - byte[] raw = (byte[]) info.GetValue ("RawData", typeof (byte[])); - Import (raw, (string)null, X509KeyStorageFlags.DefaultKeySet); - } - - - public string Issuer { - get { - X509Helper.ThrowIfContextInvalid (impl); - - if (issuer_name == null) - issuer_name = impl.GetIssuerName (false); - return issuer_name; - } - } - - public string Subject { - get { - X509Helper.ThrowIfContextInvalid (impl); - - if (subject_name == null) - subject_name = impl.GetSubjectName (false); - return subject_name; - } - } - - [ComVisible (false)] - public IntPtr Handle { - get { - if (X509Helper.IsValid (impl)) - return impl.Handle; - return IntPtr.Zero; - } - } - - - [ComVisible (false)] - public override bool Equals (object obj) - { - X509Certificate x = (obj as X509Certificate); - if (x != null) - return this.Equals (x); - return false; - } - - [MonoTODO ("X509ContentType.Pfx/Pkcs12 and SerializedCert are not supported")] - [ComVisible (false)] - public virtual byte[] Export (X509ContentType contentType) - { - X509Helper.ThrowIfContextInvalid (impl); - using (var handle = new SafePasswordHandle ((string)null)) - return impl.Export (contentType, handle); - } - - [MonoTODO ("X509ContentType.Pfx/Pkcs12 and SerializedCert are not supported")] - [ComVisible (false)] - public virtual byte[] Export (X509ContentType contentType, string password) - { - X509Helper.ThrowIfContextInvalid (impl); - using (var handle = new SafePasswordHandle (password)) - return impl.Export (contentType, handle); - } - - [MonoTODO ("X509ContentType.Pfx/Pkcs12 and SerializedCert are not supported. SecureString support is incomplete.")] - public virtual byte[] Export (X509ContentType contentType, SecureString password) - { - X509Helper.ThrowIfContextInvalid (impl); - using (var handle = new SafePasswordHandle (password)) - return impl.Export (contentType, handle); - } - - [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) - { - Reset (); - using (var handle = new SafePasswordHandle (password)) - impl = X509Helper.Import (rawData, handle, keyStorageFlags); - } - - [MonoTODO ("SecureString support is incomplete")] - public virtual void Import (byte[] rawData, SecureString password, X509KeyStorageFlags keyStorageFlags) - { - Reset (); - using (var handle = new SafePasswordHandle (password)) - impl = X509Helper.Import (rawData, handle, keyStorageFlags); - } - - [ComVisible (false)] - public virtual void Import (string fileName) - { - byte[] rawData = File.ReadAllBytes (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 = File.ReadAllBytes (fileName); - Import (rawData, password, keyStorageFlags); - } - - [MonoTODO ("SecureString support is incomplete, missing KeyStorageFlags support")] - public virtual void Import (string fileName, SecureString password, X509KeyStorageFlags keyStorageFlags) - { - byte[] rawData = File.ReadAllBytes (fileName); - Import (rawData, password, keyStorageFlags); - } - - void IDeserializationCallback.OnDeserialization (object sender) - { - } - - void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context) - { - if (!X509Helper.IsValid (impl)) - throw new NullReferenceException (); - // will throw a NRE if info is null (just like MS implementation) - info.AddValue ("RawData", impl.GetRawCertData ()); - } - - public void Dispose () - { - Dispose (true); - } - - protected virtual void Dispose (bool disposing) - { - if (disposing) - Reset (); - } - - [ComVisible (false)] - public virtual void Reset () - { - if (impl != null) { - impl.Dispose (); - impl = null; - } - - issuer_name = null; - subject_name = null; - hideDates = false; - } - } -} diff --git a/mcs/class/corlib/System.Security.Cryptography.X509Certificates/X509CertificateImpl.cs b/mcs/class/corlib/System.Security.Cryptography.X509Certificates/X509CertificateImpl.cs index e5cf47d96745..d3a2e73a9b60 100644 --- a/mcs/class/corlib/System.Security.Cryptography.X509Certificates/X509CertificateImpl.cs +++ b/mcs/class/corlib/System.Security.Cryptography.X509Certificates/X509CertificateImpl.cs @@ -51,57 +51,71 @@ protected void ThrowIfContextInvalid () public abstract X509CertificateImpl Clone (); - public abstract string GetIssuerName (bool legacyV1Mode); + public abstract string Issuer { + get; + } - public abstract string GetSubjectName (bool legacyV1Mode); + public abstract string Subject { + get; + } - public abstract byte[] GetRawCertData (); + public abstract string LegacyIssuer { + get; + } - public abstract DateTime GetValidFrom (); + public abstract string LegacySubject { + get; + } - public abstract DateTime GetValidUntil (); + public abstract byte[] RawData { + get; + } - byte[] cachedCertificateHash; + public abstract DateTime NotAfter { + get; + } - public byte[] GetCertHash () - { - ThrowIfContextInvalid (); - if (cachedCertificateHash == null) - cachedCertificateHash = GetCertHash (false); - return cachedCertificateHash; + public abstract DateTime NotBefore { + get; } - protected abstract byte[] GetCertHash (bool lazy); + public abstract byte[] Thumbprint { + get; + } - public override int GetHashCode () + public sealed override int GetHashCode () { if (!IsValid) return 0; - if (cachedCertificateHash == null) - cachedCertificateHash = GetCertHash (true); - // 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 - return 0; + byte[] thumbPrint = Thumbprint; + int value = 0; + for (int i = 0; i < thumbPrint.Length && i < 4; ++i) { + value = value << 8 | thumbPrint[i]; + } + return value; } public abstract bool Equals (X509CertificateImpl other, out bool result); - public abstract string GetKeyAlgorithm (); + public abstract string KeyAlgorithm { + get; + } - public abstract byte[] GetKeyAlgorithmParameters (); + public abstract byte[] KeyAlgorithmParameters { + get; + } - public abstract byte[] GetPublicKey (); + public abstract byte[] PublicKeyValue { + get; + } - public abstract byte[] GetSerialNumber (); + public abstract byte[] SerialNumber { + get; + } public abstract byte[] Export (X509ContentType contentType, SafePasswordHandle password); - public abstract string ToString (bool full); - - public override bool Equals (object obj) + public sealed override bool Equals (object obj) { var other = obj as X509CertificateImpl; if (other == null) @@ -110,23 +124,16 @@ public override bool Equals (object obj) if (!IsValid || !other.IsValid) return false; - bool result; - if (Equals (other, out result)) - return result; - - var ourRaw = GetRawCertData (); - var theirRaw = other.GetRawCertData (); - - if (ourRaw == null) - return theirRaw == null; - else if (theirRaw == null) + if (!Issuer.Equals (other.Issuer)) return false; - if (ourRaw.Length != theirRaw.Length) - return false; + byte[] thisSerialNumber = SerialNumber; + byte[] otherSerialNumber = other.SerialNumber; - for (int i = 0; i < ourRaw.Length; i++) { - if (ourRaw [i] != theirRaw [i]) + if (thisSerialNumber.Length != otherSerialNumber.Length) + return false; + for (int i = 0; i < thisSerialNumber.Length; i++) { + if (thisSerialNumber[i] != otherSerialNumber[i]) return false; } @@ -141,7 +148,6 @@ public void Dispose () protected virtual void Dispose (bool disposing) { - cachedCertificateHash = null; } ~X509CertificateImpl () diff --git a/mcs/class/corlib/System.Security.Cryptography.X509Certificates/X509Helper.cs b/mcs/class/corlib/System.Security.Cryptography.X509Certificates/X509Helper.cs index d347a8aaf9e8..84767b1befbb 100644 --- a/mcs/class/corlib/System.Security.Cryptography.X509Certificates/X509Helper.cs +++ b/mcs/class/corlib/System.Security.Cryptography.X509Certificates/X509Helper.cs @@ -90,8 +90,8 @@ public static bool Equals (X509CertificateImpl first, X509CertificateImpl second if (first.Equals (second, out result)) return result; - var firstRaw = first.GetRawCertData (); - var secondRaw = second.GetRawCertData (); + var firstRaw = first.RawData; + var secondRaw = second.RawData; if (firstRaw == null) return secondRaw == null; diff --git a/mcs/class/corlib/Test/System.Security.Cryptography.X509Certificates/X509CertificateTest.cs b/mcs/class/corlib/Test/System.Security.Cryptography.X509Certificates/X509CertificateTest.cs index 27dd78ec45c0..aa0f9e9a5afd 100644 --- a/mcs/class/corlib/Test/System.Security.Cryptography.X509Certificates/X509CertificateTest.cs +++ b/mcs/class/corlib/Test/System.Security.Cryptography.X509Certificates/X509CertificateTest.cs @@ -493,7 +493,8 @@ public void Certificate6 () // Certificate: basic\BADCERT.cer // - Bad certificate (will throw an exception) [Test] -[Category ("NotWorking")] // SecCertificateCreateWithData does different things on 10.11 vs 10.12 with invalid certificates https://bugzilla.xamarin.com/show_bug.cgi?id=53689 +[Category ("NotWorking")] // this test needs to be reworked +[Category ("MacNotWorking")] // SecCertificateCreateWithData does different things on 10.11 vs 10.12 with invalid certificates https://bugzilla.xamarin.com/show_bug.cgi?id=53689 public void Certificate7 () { // cannot be loaded - will throw an exception diff --git a/mcs/class/corlib/Test/System.Security.Cryptography.X509Certificates/X509SpcTest.cs b/mcs/class/corlib/Test/System.Security.Cryptography.X509Certificates/X509SpcTest.cs index 1bdc4ae2b857..c1f17901f5ca 100644 --- a/mcs/class/corlib/Test/System.Security.Cryptography.X509Certificates/X509SpcTest.cs +++ b/mcs/class/corlib/Test/System.Security.Cryptography.X509Certificates/X509SpcTest.cs @@ -1016,6 +1016,7 @@ public void ValidSignature () } [Test] + [Category ("NotWorking")] // we are now throwing due to the invalid signature public void InvalidSignature () { string filename = Path.Combine (Path.GetTempPath (), "smallspc-invalid.exe"); diff --git a/mcs/class/corlib/corlib.csproj b/mcs/class/corlib/corlib.csproj index e24331657c7a..d58600ac69b8 100644 --- a/mcs/class/corlib/corlib.csproj +++ b/mcs/class/corlib/corlib.csproj @@ -1745,7 +1745,6 @@ - diff --git a/mcs/class/corlib/corlib.dll.sources b/mcs/class/corlib/corlib.dll.sources index 82e24361c486..af20153d600d 100644 --- a/mcs/class/corlib/corlib.dll.sources +++ b/mcs/class/corlib/corlib.dll.sources @@ -707,7 +707,6 @@ System.Security.Cryptography/RSAPKCS1SignatureFormatter.cs System.Security.Cryptography/SHA1CryptoServiceProvider.cs System.Security.Cryptography/TripleDESCryptoServiceProvider.cs System.Security.Cryptography.X509Certificates/X509Certificate.cs -System.Security.Cryptography.X509Certificates/X509Certificate20.cs System.Security.Cryptography.X509Certificates/X509CertificateImpl.cs System.Security.Cryptography.X509Certificates/X509Helper.cs System.Security.Permissions/CodeAccessSecurityAttribute.cs diff --git a/mono/btls/btls-x509.c b/mono/btls/btls-x509.c index 955bb0dd195e..9f378bf6511f 100644 --- a/mono/btls/btls-x509.c +++ b/mono/btls/btls-x509.c @@ -162,9 +162,7 @@ mono_btls_x509_get_serial_number (X509 *x509, char *buffer, int size, int mono_s return 0; } - for (idx = 0; idx < len; idx++) { - buffer [idx] = *(--p); - } + memcpy (buffer, temp, len); buffer [len] = 0; OPENSSL_free (temp);