From 6beb2c1865ebf7d3381ae83c0713687c3bc980c0 Mon Sep 17 00:00:00 2001 From: Martin Baulig Date: Mon, 19 Nov 2018 17:27:15 -0500 Subject: [PATCH 1/4] "Code Ultramarine" Sync `X509Certificate2` implementation with CoreFX, similar to how we did for `X509Certificate` in "Blue" (#9650). * Introducing `X509Certificate2ImplUnix` as new common base class for `X509CertificateImplApple`, `X509CertificateImplBtls` and `X509Certificate2ImplMono`. This uses the internal `CertificateData` class from CoreFX instead of the old "fallback" implementation from "Mono.Security". * `MonoBtlsProvider`, `X509CertificateImplBtls`: the "fallback" option has been removed since we now always provide this functionality via the managed `CertificateData`. * `X509CertificateImplMono`: This has been largely stripped down to use the new `X509CertificateImplUnix`. --- .../Mono.Btls.Interface/BtlsProvider.cs | 6 +- .../Mono.Btls.Interface/BtlsX509.cs | 3 +- .../RSACertificateExtensions.cs | 8 +- mcs/class/System/Makefile | 2 +- .../Mono.AppleTls/X509CertificateImplApple.cs | 95 ++- mcs/class/System/Mono.Btls/MonoBtlsContext.cs | 5 +- .../System/Mono.Btls/MonoBtlsProvider.cs | 22 +- mcs/class/System/Mono.Btls/MonoBtlsX509.cs | 4 +- .../Mono.Btls/X509CertificateImplBtls.cs | 278 ++------ mcs/class/System/Mono/X509PalImpl.cs | 68 +- .../X509Certificate2.cs | 600 ++++++++++++------ .../X509Certificate2Impl.cs | 14 +- .../X509Certificate2ImplMono.cs | 304 +-------- .../X509Certificate2ImplUnix.cs | 259 ++++++++ .../X509ChainImplMono.cs | 17 +- .../X509Helper2.cs | 8 +- mcs/class/System/common.sources | 6 + .../X509CertificateImpl.cs | 8 + .../CryptoConfig.cs | 5 - mcs/class/corlib/corlib.dll.sources | 2 - .../cryptography/dsasignaturedeformatter.cs | 4 +- .../cryptography/dsasignatureformatter.cs | 4 +- 22 files changed, 930 insertions(+), 792 deletions(-) create mode 100644 mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2ImplUnix.cs diff --git a/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsProvider.cs b/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsProvider.cs index 0959dd0b6124..5fee46a74606 100644 --- a/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsProvider.cs +++ b/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsProvider.cs @@ -50,17 +50,17 @@ public static BtlsX509 CreateNative (byte[] data, BtlsX509Format format) public static X509Certificate CreateCertificate (byte[] data, BtlsX509Format format, bool disallowFallback = false) { - return MonoBtlsProvider.CreateCertificate (data, (MonoBtlsX509Format)format, disallowFallback); + return MonoBtlsProvider.CreateCertificate (data, (MonoBtlsX509Format)format); } public static X509Certificate2 CreateCertificate2 (byte[] data, BtlsX509Format format, bool disallowFallback = false) { - return MonoBtlsProvider.CreateCertificate2 (data, (MonoBtlsX509Format)format, disallowFallback); + return MonoBtlsProvider.CreateCertificate2 (data, (MonoBtlsX509Format)format); } public static X509Certificate2 CreateCertificate2 (byte[] data, string password, bool disallowFallback = false) { - return MonoBtlsProvider.CreateCertificate2 (data, password, disallowFallback); + return MonoBtlsProvider.CreateCertificate2 (data, password); } public static BtlsX509Chain CreateNativeChain () 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 8560e4b77a11..1ef41216e81f 100644 --- a/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509.cs +++ b/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509.cs @@ -100,7 +100,8 @@ public int GetVersion () public Oid GetSignatureAlgorithm () { - return Instance.GetSignatureAlgorithm (); + var algorithm = Instance.GetSignatureAlgorithm (); + return Oid.FromOidValue (algorithm, OidGroup.SignatureAlgorithm); } public AsnEncodedData GetPublicKeyAsn1 () diff --git a/mcs/class/System.Core/System.Security.Cryptography.X509Certificates/RSACertificateExtensions.cs b/mcs/class/System.Core/System.Security.Cryptography.X509Certificates/RSACertificateExtensions.cs index 81c303bd0913..3c04744198dd 100644 --- a/mcs/class/System.Core/System.Security.Cryptography.X509Certificates/RSACertificateExtensions.cs +++ b/mcs/class/System.Core/System.Security.Cryptography.X509Certificates/RSACertificateExtensions.cs @@ -33,8 +33,12 @@ public static class RSACertificateExtensions public static RSA GetRSAPrivateKey(this X509Certificate2 certificate) { if (certificate == null) - throw new ArgumentNullException("certificate"); - return certificate.PrivateKey as RSA; + throw new ArgumentNullException (nameof (certificate)); + + if (!certificate.HasPrivateKey) + return null; + + return certificate.Impl.GetRSAPrivateKey (); } public static RSA GetRSAPublicKey(this X509Certificate2 certificate) diff --git a/mcs/class/System/Makefile b/mcs/class/System/Makefile index adbb4ff2ecb4..dcf5bcdea349 100644 --- a/mcs/class/System/Makefile +++ b/mcs/class/System/Makefile @@ -116,7 +116,7 @@ endif TXT_RESOURCE_STRINGS = ../referencesource/System/System.txt -API_BIN_REFS := System.Net.Http System.Xml System.Core +API_BIN_REFS := System.Net.Http System.Xml System.Core System.Numerics ifndef MOBILE_PROFILE API_BIN_REFS += System.Configuration diff --git a/mcs/class/System/Mono.AppleTls/X509CertificateImplApple.cs b/mcs/class/System/Mono.AppleTls/X509CertificateImplApple.cs index ec30415d538d..bbfb1852bcd1 100644 --- a/mcs/class/System/Mono.AppleTls/X509CertificateImplApple.cs +++ b/mcs/class/System/Mono.AppleTls/X509CertificateImplApple.cs @@ -1,4 +1,3 @@ -#if MONO_FEATURE_APPLETLS || MONO_FEATURE_APPLE_X509 #if MONO_SECURITY_ALIAS extern alias MonoSecurity; #endif @@ -19,7 +18,7 @@ namespace Mono.AppleTls { - class X509CertificateImplApple : X509CertificateImpl + class X509CertificateImplApple : X509Certificate2ImplUnix { IntPtr handle; X509CertificateImpl fallback; @@ -57,18 +56,17 @@ public override X509CertificateImpl Clone () [DllImport (CFHelpers.SecurityLibrary)] extern static IntPtr SecCertificateCopyData (IntPtr cert); - 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); - } + protected 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); } } @@ -81,15 +79,6 @@ public string GetSubjectSummary () return ret; } - 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) { var otherAppleImpl = other as X509CertificateImplApple; @@ -111,52 +100,43 @@ void MustFallback () fallback = new X509Certificate2ImplMono (mxCert); } - public X509CertificateImpl FallbackImpl { - get { - MustFallback (); - return fallback; - } - } - - public override string Subject => FallbackImpl.Subject; + #region X509Certificate2Impl implementation - public override string Issuer => FallbackImpl.Issuer; + /* + * The AppleTls backend does not support X509Certificate2 yet, so we can safely throw + * PlatformNotSupportedException here. + */ - public override string LegacySubject => FallbackImpl.LegacySubject; + public override bool HasPrivateKey => throw new PlatformNotSupportedException (); - public override string LegacyIssuer => FallbackImpl.LegacyIssuer; - - public override DateTime NotAfter => FallbackImpl.NotAfter; + public override AsymmetricAlgorithm PrivateKey { + get => throw new PlatformNotSupportedException (); + set => throw new PlatformNotSupportedException (); + } - public override DateTime NotBefore => FallbackImpl.NotBefore; + public override RSA GetRSAPrivateKey () + { + throw new PlatformNotSupportedException (); + } - public override string KeyAlgorithm => FallbackImpl.KeyAlgorithm; + public override DSA GetDSAPrivateKey () + { + throw new PlatformNotSupportedException (); + } - public override byte[] KeyAlgorithmParameters => FallbackImpl.KeyAlgorithmParameters; + public override PublicKey PublicKey => throw new PlatformNotSupportedException (); - public override byte[] PublicKeyValue => FallbackImpl.PublicKeyValue; + internal override X509CertificateImplCollection IntermediateCertificates => throw new PlatformNotSupportedException (); - public override byte[] SerialNumber => FallbackImpl.SerialNumber; + internal override X509Certificate2Impl FallbackImpl => throw new PlatformNotSupportedException (); - public override byte[] Export (X509ContentType contentType, SafePasswordHandle password) + public override bool Verify (X509Certificate2 thisCertificate) { - ThrowIfContextInvalid (); - - switch (contentType) { - case X509ContentType.Cert: - return RawData; - case X509ContentType.Pfx: // this includes Pkcs12 - // TODO - throw new NotSupportedException (); - case X509ContentType.SerializedCert: - // TODO - throw new NotSupportedException (); - default: - string msg = Locale.GetText ("This certificate format '{0}' cannot be exported.", contentType); - throw new CryptographicException (msg); - } + throw new PlatformNotSupportedException (); } + #endregion + protected override void Dispose (bool disposing) { if (handle != IntPtr.Zero){ @@ -170,4 +150,3 @@ protected override void Dispose (bool disposing) } } } -#endif diff --git a/mcs/class/System/Mono.Btls/MonoBtlsContext.cs b/mcs/class/System/Mono.Btls/MonoBtlsContext.cs index 7dd92ae95e4c..1ce009bb5c8c 100644 --- a/mcs/class/System/Mono.Btls/MonoBtlsContext.cs +++ b/mcs/class/System/Mono.Btls/MonoBtlsContext.cs @@ -79,10 +79,7 @@ static X509CertificateImplBtls GetPrivateCertificate (X509Certificate certificat var password = Guid.NewGuid ().ToString (); using (var handle = new SafePasswordHandle (password)) { var buffer = certificate.Export (X509ContentType.Pfx, password); - - impl = new X509CertificateImplBtls (); - impl.Import (buffer, handle, X509KeyStorageFlags.DefaultKeySet); - return impl; + return new X509CertificateImplBtls (buffer, handle, X509KeyStorageFlags.DefaultKeySet); } } diff --git a/mcs/class/System/Mono.Btls/MonoBtlsProvider.cs b/mcs/class/System/Mono.Btls/MonoBtlsProvider.cs index d2323b0479b6..80f07e7e5339 100644 --- a/mcs/class/System/Mono.Btls/MonoBtlsProvider.cs +++ b/mcs/class/System/Mono.Btls/MonoBtlsProvider.cs @@ -119,15 +119,13 @@ internal override X509Certificate2Impl GetNativeCertificate ( return (X509Certificate2Impl)impl.Clone (); var data = certificate.GetRawCertData (); - return new X509CertificateImplBtls (data, MonoBtlsX509Format.DER, false); + return new X509CertificateImplBtls (data, MonoBtlsX509Format.DER); } internal X509Certificate2Impl GetNativeCertificate ( byte[] data, SafePasswordHandle password, X509KeyStorageFlags flags) { - var impl = new X509CertificateImplBtls (false); - impl.Import (data, password, flags); - return impl; + return new X509CertificateImplBtls (data, password, flags); } internal static MonoBtlsX509VerifyParam GetVerifyParam (MonoTlsSettings settings, string targetHost, bool serverMode) @@ -420,32 +418,30 @@ public static string GetSystemStoreLocation () #endif } - public static X509Certificate CreateCertificate (byte[] data, MonoBtlsX509Format format, bool disallowFallback = false) + public static X509Certificate CreateCertificate (byte[] data, MonoBtlsX509Format format) { - using (var impl = new X509CertificateImplBtls (data, format, disallowFallback)) { + using (var impl = new X509CertificateImplBtls (data, format)) { return new X509Certificate (impl); } } - public static X509Certificate2 CreateCertificate2 (byte[] data, MonoBtlsX509Format format, bool disallowFallback = false) + public static X509Certificate2 CreateCertificate2 (byte[] data, MonoBtlsX509Format format) { - using (var impl = new X509CertificateImplBtls (data, format, disallowFallback)) { + using (var impl = new X509CertificateImplBtls (data, format)) { return new X509Certificate2 (impl); } } public static X509Certificate2 CreateCertificate2 (byte[] data, string password, bool disallowFallback = false) { - using (var impl = new X509CertificateImplBtls (disallowFallback)) - using (var handle = new SafePasswordHandle (password)) { - impl.Import (data, handle, X509KeyStorageFlags.DefaultKeySet); + using (var handle = new SafePasswordHandle (password)) + using (var impl = new X509CertificateImplBtls (data, handle, X509KeyStorageFlags.DefaultKeySet)) return new X509Certificate2 (impl); - } } public static X509Certificate CreateCertificate (MonoBtlsX509 x509) { - using (var impl = new X509CertificateImplBtls (x509, true)) + using (var impl = new X509CertificateImplBtls (x509)) return new X509Certificate (impl); } diff --git a/mcs/class/System/Mono.Btls/MonoBtlsX509.cs b/mcs/class/System/Mono.Btls/MonoBtlsX509.cs index c722ad9fbfd3..109034c0c497 100644 --- a/mcs/class/System/Mono.Btls/MonoBtlsX509.cs +++ b/mcs/class/System/Mono.Btls/MonoBtlsX509.cs @@ -310,7 +310,7 @@ public int GetVersion () return mono_btls_x509_get_version (Handle.DangerousGetHandle ()); } - public Oid GetSignatureAlgorithm () + public string GetSignatureAlgorithm () { int size = 256; IntPtr data = Marshal.AllocHGlobal (size); @@ -318,7 +318,7 @@ public Oid GetSignatureAlgorithm () var ret = mono_btls_x509_get_signature_algorithm ( Handle.DangerousGetHandle (), data, size); CheckError (ret > 0); - return new Oid (Marshal.PtrToStringAnsi (data)); + return Marshal.PtrToStringAnsi (data); } finally { Marshal.FreeHGlobal (data); } diff --git a/mcs/class/System/Mono.Btls/X509CertificateImplBtls.cs b/mcs/class/System/Mono.Btls/X509CertificateImplBtls.cs index 9aa3f5519453..b7ad40ca628c 100644 --- a/mcs/class/System/Mono.Btls/X509CertificateImplBtls.cs +++ b/mcs/class/System/Mono.Btls/X509CertificateImplBtls.cs @@ -39,6 +39,7 @@ using System; using System.Text; using System.Collections; +using System.Collections.Generic; using System.Security; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; @@ -47,44 +48,67 @@ namespace Mono.Btls { - class X509CertificateImplBtls : X509Certificate2Impl + class X509CertificateImplBtls : X509Certificate2ImplUnix { MonoBtlsX509 x509; MonoBtlsKey nativePrivateKey; - X500DistinguishedName subjectName; - X500DistinguishedName issuerName; X509CertificateImplCollection intermediateCerts; PublicKey publicKey; - bool archived; - bool disallowFallback; - internal X509CertificateImplBtls (bool disallowFallback = false) + internal X509CertificateImplBtls () { - this.disallowFallback = disallowFallback; } - internal X509CertificateImplBtls (MonoBtlsX509 x509, bool disallowFallback = false) + internal X509CertificateImplBtls (MonoBtlsX509 x509) { - this.disallowFallback = disallowFallback; this.x509 = x509.Copy (); } X509CertificateImplBtls (X509CertificateImplBtls other) { - disallowFallback = other.disallowFallback; x509 = other.x509 != null ? other.x509.Copy () : null; nativePrivateKey = other.nativePrivateKey != null ? other.nativePrivateKey.Copy () : null; - fallback = other.fallback != null ? (X509Certificate2Impl)other.fallback.Clone () : null; if (other.intermediateCerts != null) intermediateCerts = other.intermediateCerts.Clone (); } - internal X509CertificateImplBtls (byte[] data, MonoBtlsX509Format format, bool disallowFallback = false) + internal X509CertificateImplBtls (byte[] data, MonoBtlsX509Format format) { - this.disallowFallback = disallowFallback; x509 = MonoBtlsX509.LoadFromData (data, format); } + internal X509CertificateImplBtls (byte[] data, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags) + { + if (password == null || password.IsInvalid) { + try { + Import (data); + } catch (Exception e) { + try { + ImportPkcs12 (data, null); + } catch { + string msg = Locale.GetText ("Unable to decode certificate."); + // inner exception is the original (not second) exception + throw new CryptographicException (msg, e); + } + } + } else { + // try PKCS#12 + try { + ImportPkcs12 (data, password); + } catch (Exception e) { + try { + // it's possible to supply a (unrequired/unusued) password + // fix bug #79028 + Import (data); + } catch { + string msg = Locale.GetText ("Unable to decode certificate."); + // inner exception is the original (not second) exception + throw new CryptographicException (msg, e); + } + } + } + } + public override bool IsValid { get { return x509 != null && x509.IsValid; } } @@ -108,12 +132,6 @@ internal MonoBtlsX509 X509 { internal MonoBtlsKey NativePrivateKey { get { ThrowIfContextInvalid (); - if (nativePrivateKey == null && FallbackImpl.HasPrivateKey) { - var key = FallbackImpl.PrivateKey as RSA; - if (key == null) - throw new NotSupportedException ("Currently only supports RSA private keys."); - nativePrivateKey = MonoBtlsKey.CreateFromRSAPrivateKey (key); - } return nativePrivateKey; } } @@ -136,29 +154,11 @@ public override bool Equals (X509CertificateImpl other, out bool result) return true; } - public override byte[] Thumbprint => X509.GetCertHash (); - - public override byte[] RawData => X509.GetRawData (MonoBtlsX509Format.DER); - - public override string Subject => SubjectName.Name; - - public override string Issuer => IssuerName.Name; - - public override string LegacySubject => SubjectName.Decode (X500DistinguishedNameFlags.None); - - public override string LegacyIssuer => IssuerName.Decode (X500DistinguishedNameFlags.None); - - public override DateTime NotBefore => X509.GetNotBefore ().ToLocalTime (); - - public override DateTime NotAfter => X509.GetNotAfter ().ToLocalTime (); - - public override byte[] PublicKeyValue => X509.GetPublicKeyData (); - - public override byte[] SerialNumber => X509.GetSerialNumber (true); - - public override string KeyAlgorithm => PublicKey.Oid.Value; - - public override byte[] KeyAlgorithmParameters => PublicKey.EncodedParameters.RawData; + protected override byte[] GetRawCertData () + { + ThrowIfContextInvalid (); + return X509.GetRawData (MonoBtlsX509Format.DER); + } internal override X509CertificateImplCollection IntermediateCertificates { get { return intermediateCerts; } @@ -174,65 +174,14 @@ protected override void Dispose (bool disposing) #region X509Certificate2Impl - X509Certificate2Impl fallback; + internal override X509Certificate2Impl FallbackImpl => throw new InvalidOperationException (); - void MustFallback () - { - if (disallowFallback) - throw new InvalidOperationException (); - if (fallback != null) - return; - fallback = SystemDependencyProvider.Instance.CertificateProvider.Import ( - RawData, null, X509KeyStorageFlags.DefaultKeySet, - CertificateImportFlags.DisableNativeBackend); - } - - internal override X509Certificate2Impl FallbackImpl { - get { - MustFallback (); - return fallback; - } - } - - [MonoTODO] - public override bool Archived { - get { - ThrowIfContextInvalid (); - return archived; - } - set { - ThrowIfContextInvalid (); - archived = value; - } - } - - public override X509ExtensionCollection Extensions { - get { return FallbackImpl.Extensions; } - } - - public override bool HasPrivateKey { - get { return nativePrivateKey != null || FallbackImpl.HasPrivateKey; } - } - - public override X500DistinguishedName IssuerName { - get { - ThrowIfContextInvalid (); - if (issuerName == null) { - using (var xname = x509.GetIssuerName ()) { - var encoding = xname.GetRawData (false); - var canonEncoding = xname.GetRawData (true); - var name = MonoBtlsUtils.FormatName (xname, true, ", ", true); - issuerName = new X500DistinguishedName (encoding, canonEncoding, name); - } - } - return issuerName; - } - } + public override bool HasPrivateKey => nativePrivateKey != null; public override AsymmetricAlgorithm PrivateKey { get { - if (nativePrivateKey == null || !nativePrivateKey.IsRsa) - return FallbackImpl.PrivateKey; + if (nativePrivateKey == null) + return null; var bytes = nativePrivateKey.GetBytes (true); return PKCS8.PrivateKeyInfo.DecodeRSA (bytes); } @@ -240,10 +189,22 @@ public override AsymmetricAlgorithm PrivateKey { if (nativePrivateKey != null) nativePrivateKey.Dispose (); nativePrivateKey = null; - FallbackImpl.PrivateKey = value; } } + public override RSA GetRSAPrivateKey () + { + if (nativePrivateKey == null) + return null; + var bytes = nativePrivateKey.GetBytes (true); + return PKCS8.PrivateKeyInfo.DecodeRSA (bytes); + } + + public override DSA GetDSAPrivateKey () + { + throw new PlatformNotSupportedException (); + } + public override PublicKey PublicKey { get { ThrowIfContextInvalid (); @@ -256,70 +217,6 @@ public override PublicKey PublicKey { } } - public override Oid SignatureAlgorithm { - get { - ThrowIfContextInvalid (); - return X509.GetSignatureAlgorithm (); - } - } - - public override X500DistinguishedName SubjectName { - get { - ThrowIfContextInvalid (); - if (subjectName == null) { - using (var xname = x509.GetSubjectName ()) { - var encoding = xname.GetRawData (false); - var canonEncoding = xname.GetRawData (true); - var name = MonoBtlsUtils.FormatName (xname, true, ", ", true); - subjectName = new X500DistinguishedName (encoding, canonEncoding, name); - } - } - return subjectName; - } - } - - public override int Version { - get { return X509.GetVersion (); } - } - - public override string GetNameInfo (X509NameType nameType, bool forIssuer) - { - return FallbackImpl.GetNameInfo (nameType, forIssuer); - } - - public override void Import (byte[] data, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags) - { - Reset (); - if (password == null || password.IsInvalid) { - try { - Import (data); - } catch (Exception e) { - try { - ImportPkcs12 (data, null); - } catch { - string msg = Locale.GetText ("Unable to decode certificate."); - // inner exception is the original (not second) exception - throw new CryptographicException (msg, e); - } - } - } else { - // try PKCS#12 - try { - ImportPkcs12 (data, password); - } catch (Exception e) { - try { - // it's possible to supply a (unrequired/unusued) password - // fix bug #79028 - Import (data); - } catch { - string msg = Locale.GetText ("Unable to decode certificate."); - // inner exception is the original (not second) exception - throw new CryptographicException (msg, e); - } - } - } - } - void Import (byte[] data) { if (data != null) { @@ -356,7 +253,7 @@ void ImportPkcs12 (byte[] data, SafePasswordHandle password) using (var ic = pkcs12.GetCertificate (i)) { if (MonoBtlsX509.Compare (ic, x509) == 0) continue; - var impl = new X509CertificateImplBtls (ic, true); + var impl = new X509CertificateImplBtls (ic); intermediateCerts.Add (impl, true); } } @@ -364,56 +261,6 @@ void ImportPkcs12 (byte[] data, SafePasswordHandle password) } } - public override byte[] Export (X509ContentType contentType, SafePasswordHandle password) - { - ThrowIfContextInvalid (); - - switch (contentType) { - case X509ContentType.Cert: - return RawData; - case X509ContentType.Pfx: // this includes Pkcs12 - return ExportPkcs12 (password); - case X509ContentType.SerializedCert: - // TODO - throw new NotSupportedException (); - default: - string msg = Locale.GetText ("This certificate format '{0}' cannot be exported.", contentType); - throw new CryptographicException (msg); - } - } - - byte[] ExportPkcs12 (SafePasswordHandle password) - { - if (password == null || password.IsInvalid) - return ExportPkcs12 ((string)null); - var passwordString = password.Mono_DangerousGetString (); - return ExportPkcs12 (passwordString); - } - - byte[] ExportPkcs12 (string password) - { - var pfx = new MX.PKCS12 (); - try { - var attrs = new Hashtable (); - var localKeyId = new ArrayList (); - localKeyId.Add (new byte[] { 1, 0, 0, 0 }); - attrs.Add (MX.PKCS9.localKeyId, localKeyId); - if (password != null) - pfx.Password = password; - 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].RawData)); - } - var privateKey = PrivateKey; - if (privateKey != null) - pfx.AddPkcs8ShroudedKeyBag (privateKey, attrs); - return pfx.GetBytes (); - } finally { - pfx.Password = null; - } - } - public override bool Verify (X509Certificate2 thisCertificate) { using (var chain = new MonoBtlsX509Chain ()) { @@ -438,13 +285,8 @@ public override void Reset () nativePrivateKey.Dispose (); nativePrivateKey = null; } - subjectName = null; - issuerName = null; - archived = false; publicKey = null; intermediateCerts = null; - if (fallback != null) - fallback.Reset (); } #endregion diff --git a/mcs/class/System/Mono/X509PalImpl.cs b/mcs/class/System/Mono/X509PalImpl.cs index e9656ce0ae5e..2afbee8da4d4 100644 --- a/mcs/class/System/Mono/X509PalImpl.cs +++ b/mcs/class/System/Mono/X509PalImpl.cs @@ -23,6 +23,13 @@ // 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. +#if MONO_SECURITY_ALIAS +extern alias MonoSecurity; +using MonoSecurity::Mono.Security; +#else +using Mono.Security; +#endif + using System; using System.IO; using System.Text; @@ -72,17 +79,66 @@ internal X509Certificate2Impl ImportFallback (byte[] data) { data = ConvertData (data); - var impl = new X509Certificate2ImplMono (); using (var handle = new SafePasswordHandle ((string)null)) - impl.Import (data, handle, X509KeyStorageFlags.DefaultKeySet); - return impl; + return new X509Certificate2ImplMono (data, handle, X509KeyStorageFlags.DefaultKeySet); } internal X509Certificate2Impl ImportFallback (byte[] data, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags) { - var impl = new X509Certificate2ImplMono (); - impl.Import (data, password, keyStorageFlags); - return impl; + return new X509Certificate2ImplMono (data, password, keyStorageFlags); + } + + public bool SupportsLegacyBasicConstraintsExtension => false; + + static byte[] signedData = new byte[] { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02 }; + + public X509ContentType GetCertContentType (byte[] rawData) + { + if ((rawData == null) || (rawData.Length == 0)) + throw new ArgumentException ("rawData"); + + if (rawData[0] == 0x30) { + // ASN.1 SEQUENCE + try { + ASN1 data = new ASN1 (rawData); + + // SEQUENCE / SEQUENCE / BITSTRING + if (data.Count == 3 && data[0].Tag == 0x30 && data[1].Tag == 0x30 && data[2].Tag == 0x03) + return X509ContentType.Cert; + + // INTEGER / SEQUENCE / SEQUENCE + if (data.Count == 3 && data[0].Tag == 0x02 && data[1].Tag == 0x30 && data[2].Tag == 0x30) + return X509ContentType.Pkcs12; // note: Pfx == Pkcs12 + + // check for PKCS#7 (count unknown but greater than 0) + // SEQUENCE / OID (signedData) + if (data.Count > 0 && data[0].Tag == 0x06 && data[0].CompareValue (signedData)) + return X509ContentType.Pkcs7; + + return X509ContentType.Unknown; + } catch (Exception) { + return X509ContentType.Unknown; + } + } else { + string pem = Encoding.ASCII.GetString (rawData); + int start = pem.IndexOf ("-----BEGIN CERTIFICATE-----"); + if (start >= 0) + return X509ContentType.Cert; + } + + return X509ContentType.Unknown; + } + + public X509ContentType GetCertContentType (string fileName) + { + if (fileName == null) + throw new ArgumentNullException ("fileName"); + if (fileName.Length == 0) + throw new ArgumentException ("fileName"); + + byte[] data = File.ReadAllBytes (fileName); + return GetCertContentType (data); } + } } diff --git a/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2.cs b/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2.cs index f6237b7e6a1e..dfe76a55a05e 100644 --- a/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2.cs +++ b/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2.cs @@ -43,30 +43,44 @@ using System.Collections; using System.Runtime.Serialization; using Microsoft.Win32.SafeHandles; +using Internal.Cryptography; using Mono; -namespace System.Security.Cryptography.X509Certificates { - +namespace System.Security.Cryptography.X509Certificates +{ [Serializable] - public class X509Certificate2 : X509Certificate { - - new internal X509Certificate2Impl Impl { - get { - var impl2 = base.Impl as X509Certificate2Impl; - X509Helper.ThrowIfContextInvalid (impl2); - return impl2; - } - } - - string friendlyName = string.Empty; + public class X509Certificate2 : X509Certificate + { + volatile byte[] lazyRawData; + volatile Oid lazySignatureAlgorithm; + volatile int lazyVersion; + volatile X500DistinguishedName lazySubjectName; + volatile X500DistinguishedName lazyIssuerName; + volatile PublicKey lazyPublicKey; + volatile AsymmetricAlgorithm lazyPrivateKey; + volatile X509ExtensionCollection lazyExtensions; + + public override void Reset () + { + lazyRawData = null; + lazySignatureAlgorithm = null; + lazyVersion = 0; + lazySubjectName = null; + lazyIssuerName = null; + lazyPublicKey = null; + lazyPrivateKey = null; + lazyExtensions = null; - // constructors + base.Reset (); + } public X509Certificate2 () + : base () { } public X509Certificate2 (byte[] rawData) + : base (rawData) { // MONO: temporary hack until `X509CertificateImplApple` derives from // `X509Certificate2Impl`. @@ -83,6 +97,7 @@ public X509Certificate2 (byte[] rawData, string password) { } + [CLSCompliantAttribute (false)] public X509Certificate2 (byte[] rawData, SecureString password) : base (rawData, password) { @@ -93,11 +108,22 @@ public X509Certificate2 (byte[] rawData, string password, X509KeyStorageFlags ke { } + [CLSCompliantAttribute (false)] public X509Certificate2 (byte[] rawData, SecureString password, X509KeyStorageFlags keyStorageFlags) : base (rawData, password, keyStorageFlags) { } + public X509Certificate2 (IntPtr handle) + : base (handle) + { + } + + internal X509Certificate2 (X509Certificate2Impl impl) + : base (impl) + { + } + public X509Certificate2 (string fileName) : base (fileName) { @@ -123,275 +149,483 @@ public X509Certificate2 (string fileName, SecureString password, X509KeyStorageF { } - public X509Certificate2 (IntPtr handle) : base (handle) - { - throw new PlatformNotSupportedException (); - } - public X509Certificate2 (X509Certificate certificate) : base (certificate) { } - protected X509Certificate2 (SerializationInfo info, StreamingContext context) : base (info, context) - { - } - - internal X509Certificate2 (X509Certificate2Impl impl) - : base (impl) + protected X509Certificate2 (SerializationInfo info, StreamingContext context) + : base (info, context) { + throw new PlatformNotSupportedException (); } - // properties - public bool Archived { - get { return Impl.Archived; } - set { Impl.Archived = true; } + get { + ThrowIfInvalid (); + return Impl.Archived; + } + + set { + ThrowIfInvalid (); + Impl.Archived = value; + } } public X509ExtensionCollection Extensions { - get { return Impl.Extensions; } + get { + ThrowIfInvalid (); + + X509ExtensionCollection extensions = lazyExtensions; + if (extensions == null) { + extensions = new X509ExtensionCollection (); + foreach (X509Extension extension in Impl.Extensions) { + X509Extension customExtension = CreateCustomExtensionIfAny (extension.Oid); + if (customExtension == null) { + extensions.Add (extension); + } else { + customExtension.CopyFrom (extension); + extensions.Add (customExtension); + } + } + lazyExtensions = extensions; + } + return extensions; + } } public string FriendlyName { get { ThrowIfInvalid (); - return friendlyName; + return Impl.FriendlyName; } + set { ThrowIfInvalid (); - friendlyName = value; + Impl.FriendlyName = value; } } public bool HasPrivateKey { - get { return Impl.HasPrivateKey; } + get { + ThrowIfInvalid (); + return Impl.HasPrivateKey; + } + } + + public AsymmetricAlgorithm PrivateKey { + get { + ThrowIfInvalid (); + + if (!HasPrivateKey) + return null; + + if (lazyPrivateKey == null) { + switch (GetKeyAlgorithm ()) { + case Oids.RsaRsa: + lazyPrivateKey = Impl.GetRSAPrivateKey (); + break; + case Oids.DsaDsa: + lazyPrivateKey = Impl.GetDSAPrivateKey (); + break; + default: + // This includes ECDSA, because an Oids.Ecc key can be + // many different algorithm kinds, not necessarily with mutual exclusion. + // + // Plus, .NET Framework only supports RSA and DSA in this property. + throw new NotSupportedException (SR.NotSupported_KeyAlgorithm); + } + } + + return lazyPrivateKey; + } + set { + throw new PlatformNotSupportedException (); + } } public X500DistinguishedName IssuerName { - get { return Impl.IssuerName; } - } + get { + ThrowIfInvalid (); + + X500DistinguishedName issuerName = lazyIssuerName; + if (issuerName == null) + issuerName = lazyIssuerName = Impl.IssuerName; + return issuerName; + } + } public DateTime NotAfter { - get { return Impl.NotAfter.ToLocalTime (); } + get { return GetNotAfter (); } } public DateTime NotBefore { - get { return Impl.NotBefore.ToLocalTime (); } + get { return GetNotBefore (); } } - public AsymmetricAlgorithm PrivateKey { - get { return Impl.PrivateKey; } - set { - throw new PlatformNotSupportedException (); + public PublicKey PublicKey { + get { + ThrowIfInvalid (); + + PublicKey publicKey = lazyPublicKey; + if (publicKey == null) { + string keyAlgorithmOid = GetKeyAlgorithm (); + byte[] parameters = GetKeyAlgorithmParameters (); + byte[] keyValue = GetPublicKey (); + Oid oid = new Oid (keyAlgorithmOid); + publicKey = lazyPublicKey = new PublicKey (oid, new AsnEncodedData (oid, parameters), new AsnEncodedData (oid, keyValue)); + } + return publicKey; } } - public PublicKey PublicKey { - get { return Impl.PublicKey; } - } - public byte[] RawData { - get { return GetRawCertData (); } + get { + ThrowIfInvalid (); + + byte[] rawData = lazyRawData; + if (rawData == null) + rawData = lazyRawData = Impl.RawData; + return rawData.CloneByteArray (); + } } public string SerialNumber { - get { return GetSerialNumberString (); } - } + get { + return GetSerialNumberString (); + } + } public Oid SignatureAlgorithm { - get { return Impl.SignatureAlgorithm; } - } + get { + ThrowIfInvalid (); + + Oid signatureAlgorithm = lazySignatureAlgorithm; + if (signatureAlgorithm == null) { + string oidValue = Impl.SignatureAlgorithm; + signatureAlgorithm = lazySignatureAlgorithm = Oid.FromOidValue (oidValue, OidGroup.SignatureAlgorithm); + } + return signatureAlgorithm; + } + } public X500DistinguishedName SubjectName { - get { return Impl.SubjectName; } - } + get { + ThrowIfInvalid (); - public string Thumbprint { - get { return GetCertHashString (); } - } + X500DistinguishedName subjectName = lazySubjectName; + if (subjectName == null) + subjectName = lazySubjectName = Impl.SubjectName; + return subjectName; + } + } - public int Version { - get { return Impl.Version; } + public string Thumbprint { + get { + byte[] thumbPrint = GetCertHash (); + return thumbPrint.ToHexStringUpper (); + } } - // methods + public int Version { + get { + ThrowIfInvalid (); - [MonoTODO ("always return String.Empty for UpnName, DnsFromAlternativeName and UrlName")] - public string GetNameInfo (X509NameType nameType, bool forIssuer) - { - return Impl.GetNameInfo (nameType, forIssuer); + int version = lazyVersion; + if (version == 0) + version = lazyVersion = Impl.Version; + return version; + } } - public override void Import (byte[] rawData) + public static X509ContentType GetCertContentType (byte[] rawData) { - base.Import (rawData); + if (rawData == null || rawData.Length == 0) + throw new ArgumentException (SR.Arg_EmptyOrNullArray, nameof (rawData)); + + return X509Pal.Instance.GetCertContentType (rawData); } - public override void Import (byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags) + public static X509ContentType GetCertContentType (string fileName) { - base.Import (rawData, password, keyStorageFlags); + if (fileName == null) + throw new ArgumentNullException (nameof (fileName)); + + // Desktop compat: The desktop CLR expands the filename to a full path for the purpose of performing a CAS permission check. While CAS is not present here, + // we still need to call GetFullPath() so we get the same exception behavior if the fileName is bad. + string fullPath = Path.GetFullPath (fileName); + + return X509Pal.Instance.GetCertContentType (fileName); } - public override void Import (byte[] rawData, SecureString password, X509KeyStorageFlags keyStorageFlags) + public string GetNameInfo (X509NameType nameType, bool forIssuer) { - base.Import (rawData, password, keyStorageFlags); + return Impl.GetNameInfo (nameType, forIssuer); } - public override void Import (string fileName) + public override string ToString () { - base.Import (fileName); + return base.ToString (fVerbose: true); } - public override void Import (string fileName, string password, X509KeyStorageFlags keyStorageFlags) + public override string ToString (bool verbose) { - base.Import (fileName, password, keyStorageFlags); + if (verbose == false || !IsValid) + return ToString (); + + StringBuilder sb = new StringBuilder (); + + // Version + sb.AppendLine ("[Version]"); + sb.Append (" V"); + sb.Append (Version); + + // Subject + sb.AppendLine (); + sb.AppendLine (); + sb.AppendLine ("[Subject]"); + sb.Append (" "); + sb.Append (SubjectName.Name); + string simpleName = GetNameInfo (X509NameType.SimpleName, false); + if (simpleName.Length > 0) { + sb.AppendLine (); + sb.Append (" "); + sb.Append ("Simple Name: "); + sb.Append (simpleName); + } + string emailName = GetNameInfo (X509NameType.EmailName, false); + if (emailName.Length > 0) { + sb.AppendLine (); + sb.Append (" "); + sb.Append ("Email Name: "); + sb.Append (emailName); + } + string upnName = GetNameInfo (X509NameType.UpnName, false); + if (upnName.Length > 0) { + sb.AppendLine (); + sb.Append (" "); + sb.Append ("UPN Name: "); + sb.Append (upnName); + } + string dnsName = GetNameInfo (X509NameType.DnsName, false); + if (dnsName.Length > 0) { + sb.AppendLine (); + sb.Append (" "); + sb.Append ("DNS Name: "); + sb.Append (dnsName); + } + + // Issuer + sb.AppendLine (); + sb.AppendLine (); + sb.AppendLine ("[Issuer]"); + sb.Append (" "); + sb.Append (IssuerName.Name); + simpleName = GetNameInfo (X509NameType.SimpleName, true); + if (simpleName.Length > 0) { + sb.AppendLine (); + sb.Append (" "); + sb.Append ("Simple Name: "); + sb.Append (simpleName); + } + emailName = GetNameInfo (X509NameType.EmailName, true); + if (emailName.Length > 0) { + sb.AppendLine (); + sb.Append (" "); + sb.Append ("Email Name: "); + sb.Append (emailName); + } + upnName = GetNameInfo (X509NameType.UpnName, true); + if (upnName.Length > 0) { + sb.AppendLine (); + sb.Append (" "); + sb.Append ("UPN Name: "); + sb.Append (upnName); + } + dnsName = GetNameInfo (X509NameType.DnsName, true); + if (dnsName.Length > 0) { + sb.AppendLine (); + sb.Append (" "); + sb.Append ("DNS Name: "); + sb.Append (dnsName); + } + + // Serial Number + sb.AppendLine (); + sb.AppendLine (); + sb.AppendLine ("[Serial Number]"); + sb.Append (" "); + sb.AppendLine (SerialNumber); + + // NotBefore + sb.AppendLine (); + sb.AppendLine ("[Not Before]"); + sb.Append (" "); + sb.AppendLine (FormatDate (NotBefore)); + + // NotAfter + sb.AppendLine (); + sb.AppendLine ("[Not After]"); + sb.Append (" "); + sb.AppendLine (FormatDate (NotAfter)); + + // Thumbprint + sb.AppendLine (); + sb.AppendLine ("[Thumbprint]"); + sb.Append (" "); + sb.AppendLine (Thumbprint); + + // Signature Algorithm + sb.AppendLine (); + sb.AppendLine ("[Signature Algorithm]"); + sb.Append (" "); + sb.Append (SignatureAlgorithm.FriendlyName); + sb.Append ('('); + sb.Append (SignatureAlgorithm.Value); + sb.AppendLine (")"); + + // Public Key + sb.AppendLine (); + sb.Append ("[Public Key]"); + // It could throw if it's some user-defined CryptoServiceProvider + try { + PublicKey pubKey = PublicKey; + + sb.AppendLine (); + sb.Append (" "); + sb.Append ("Algorithm: "); + sb.Append (pubKey.Oid.FriendlyName); + // So far, we only support RSACryptoServiceProvider & DSACryptoServiceProvider Keys + try { + sb.AppendLine (); + sb.Append (" "); + sb.Append ("Length: "); + + using (RSA pubRsa = this.GetRSAPublicKey ()) { + if (pubRsa != null) { + sb.Append (pubRsa.KeySize); + } + } + } catch (NotSupportedException) { + } + + sb.AppendLine (); + sb.Append (" "); + sb.Append ("Key Blob: "); + sb.AppendLine (pubKey.EncodedKeyValue.Format (true)); + + sb.Append (" "); + sb.Append ("Parameters: "); + sb.Append (pubKey.EncodedParameters.Format (true)); + } catch (CryptographicException) { + } + + // Private key + Impl.AppendPrivateKeyInfo (sb); + + // Extensions + X509ExtensionCollection extensions = Extensions; + if (extensions.Count > 0) { + sb.AppendLine (); + sb.AppendLine (); + sb.Append ("[Extensions]"); + foreach (X509Extension extension in extensions) { + try { + sb.AppendLine (); + sb.Append ("* "); + sb.Append (extension.Oid.FriendlyName); + sb.Append ('('); + sb.Append (extension.Oid.Value); + sb.Append ("):"); + + sb.AppendLine (); + sb.Append (" "); + sb.Append (extension.Format (true)); + } catch (CryptographicException) { + } + } + } + + sb.AppendLine (); + return sb.ToString (); } - public override void Import (string fileName, SecureString password, X509KeyStorageFlags keyStorageFlags) + public override void Import (byte[] rawData) { - base.Import (fileName, password, keyStorageFlags); + base.Import (rawData); } - [MonoTODO ("X509ContentType.SerializedCert is not supported")] - public override byte[] Export (X509ContentType contentType, string password) + public override void Import (byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags) { - X509Helper.ThrowIfContextInvalid (Impl); - using (var handle = new SafePasswordHandle (password)) { - return Impl.Export (contentType, handle); - } + base.Import (rawData, password, keyStorageFlags); } - public override void Reset () + [CLSCompliantAttribute (false)] + public override void Import (byte[] rawData, SecureString password, X509KeyStorageFlags keyStorageFlags) { - friendlyName = string.Empty; - base.Reset (); + base.Import (rawData, password, keyStorageFlags); } - public override string ToString () + public override void Import (string fileName) { - if (!IsValid) - return "System.Security.Cryptography.X509Certificates.X509Certificate2"; - return base.ToString (true); + base.Import (fileName); } - public override string ToString (bool verbose) + public override void Import (string fileName, string password, X509KeyStorageFlags keyStorageFlags) { - if (!IsValid) - return "System.Security.Cryptography.X509Certificates.X509Certificate2"; - - // the non-verbose X509Certificate2 == verbose X509Certificate - if (!verbose) - return base.ToString (true); - - string nl = Environment.NewLine; - StringBuilder sb = new StringBuilder (); - sb.AppendFormat ("[Version]{0} V{1}{0}{0}", nl, Version); - sb.AppendFormat ("[Subject]{0} {1}{0}{0}", nl, Subject); - sb.AppendFormat ("[Issuer]{0} {1}{0}{0}", nl, Issuer); - sb.AppendFormat ("[Serial Number]{0} {1}{0}{0}", nl, SerialNumber); - sb.AppendFormat ("[Not Before]{0} {1}{0}{0}", nl, NotBefore); - sb.AppendFormat ("[Not After]{0} {1}{0}{0}", nl, NotAfter); - sb.AppendFormat ("[Thumbprint]{0} {1}{0}{0}", nl, Thumbprint); - 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 (); + base.Import (fileName, password, keyStorageFlags); } - private static void AppendBuffer (StringBuilder sb, byte[] buffer) + [CLSCompliantAttribute (false)] + public override void Import (string fileName, SecureString password, X509KeyStorageFlags keyStorageFlags) { - 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 (" "); - } + base.Import (fileName, password, keyStorageFlags); } - [MonoTODO ("by default this depends on the incomplete X509Chain")] + #region Mono Implementation + public bool Verify () { return Impl.Verify (this); } - // static methods - - private static byte[] signedData = new byte[] { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02 }; + #endregion - [MonoTODO ("Detection limited to Cert, Pfx/Pkcs12, Pkcs7 and Unknown")] - public static X509ContentType GetCertContentType (byte[] rawData) + static X509Extension CreateCustomExtensionIfAny (Oid oid) { - if ((rawData == null) || (rawData.Length == 0)) - throw new ArgumentException ("rawData"); + string oidValue = oid.Value; + switch (oidValue) { + case Oids.BasicConstraints: + return X509Pal.Instance.SupportsLegacyBasicConstraintsExtension ? + new X509BasicConstraintsExtension () : + null; - if (rawData[0] == 0x30) { - // ASN.1 SEQUENCE - try { - ASN1 data = new ASN1 (rawData); - - // SEQUENCE / SEQUENCE / BITSTRING - if (data.Count == 3 && data [0].Tag == 0x30 && data [1].Tag == 0x30 && data [2].Tag == 0x03) - return X509ContentType.Cert; - - // INTEGER / SEQUENCE / SEQUENCE - if (data.Count == 3 && data [0].Tag == 0x02 && data [1].Tag == 0x30 && data [2].Tag == 0x30) - return X509ContentType.Pkcs12; // note: Pfx == Pkcs12 - - // check for PKCS#7 (count unknown but greater than 0) - // SEQUENCE / OID (signedData) - if (data.Count > 0 && data [0].Tag == 0x06 && data [0].CompareValue (signedData)) - return X509ContentType.Pkcs7; - - return X509ContentType.Unknown; - } - catch (Exception) { - return X509ContentType.Unknown; - } - } else { - string pem = Encoding.ASCII.GetString (rawData); - int start = pem.IndexOf ("-----BEGIN CERTIFICATE-----"); - if (start >= 0) - return X509ContentType.Cert; - } + case Oids.BasicConstraints2: + return new X509BasicConstraintsExtension (); - return X509ContentType.Unknown; - } + case Oids.KeyUsage: + return new X509KeyUsageExtension (); - [MonoTODO ("Detection limited to Cert, Pfx, Pkcs12 and Unknown")] - public static X509ContentType GetCertContentType (string fileName) - { - if (fileName == null) - throw new ArgumentNullException ("fileName"); - if (fileName.Length == 0) - throw new ArgumentException ("fileName"); + case Oids.EnhancedKeyUsage: + return new X509EnhancedKeyUsageExtension (); + + case Oids.SubjectKeyIdentifier: + return new X509SubjectKeyIdentifierExtension (); - byte[] data = File.ReadAllBytes (fileName); - return GetCertContentType (data); + default: + return null; + } } - // internal stuff because X509Certificate2 isn't complete enough - // (maybe X509Certificate3 will be better?) + // + // MARTIN CHECK POINT + // - [MonoTODO ("See comment in X509Helper2.GetMonoCertificate().")] - internal MX.X509Certificate MonoCertificate { + new internal X509Certificate2Impl Impl { get { - return X509Helper2.GetMonoCertificate (this); + var impl2 = base.Impl as X509Certificate2Impl; + X509Helper.ThrowIfContextInvalid (impl2); + return impl2; } } } diff --git a/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2Impl.cs b/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2Impl.cs index 76ee659fa96d..a454ea07ada9 100644 --- a/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2Impl.cs +++ b/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2Impl.cs @@ -25,6 +25,8 @@ // 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.Text; +using System.Collections.Generic; using Microsoft.Win32.SafeHandles; namespace System.Security.Cryptography.X509Certificates @@ -35,12 +37,12 @@ public abstract bool Archived { get; set; } - public abstract X509ExtensionCollection Extensions { + public abstract IEnumerable Extensions { get; } - public abstract bool HasPrivateKey { - get; + public abstract string FriendlyName { + get; set; } public abstract X500DistinguishedName IssuerName { @@ -55,7 +57,7 @@ public abstract PublicKey PublicKey { get; } - public abstract Oid SignatureAlgorithm { + public abstract string SignatureAlgorithm { get; } @@ -77,10 +79,10 @@ internal abstract X509Certificate2Impl FallbackImpl { public abstract string GetNameInfo (X509NameType nameType, bool forIssuer); - public abstract void Import (byte[] rawData, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags); - public abstract bool Verify (X509Certificate2 thisCertificate); + public abstract void AppendPrivateKeyInfo (StringBuilder sb); + public abstract void Reset (); } } diff --git a/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2ImplMono.cs b/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2ImplMono.cs index de2e7d350cea..f10549bd5c79 100644 --- a/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2ImplMono.cs +++ b/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2ImplMono.cs @@ -43,19 +43,15 @@ using System.IO; using System.Text; using System.Collections; +using System.Collections.Generic; using System.Runtime.InteropServices; using Microsoft.Win32.SafeHandles; namespace System.Security.Cryptography.X509Certificates { - internal class X509Certificate2ImplMono : X509Certificate2Impl + internal class X509Certificate2ImplMono : X509Certificate2ImplUnix { - bool _archived; - X509ExtensionCollection _extensions; PublicKey _publicKey; - X500DistinguishedName issuer_name; - X500DistinguishedName subject_name; - Oid signature_algorithm; X509CertificateImplCollection intermediateCerts; MX.X509Certificate _cert; @@ -89,6 +85,24 @@ public X509Certificate2ImplMono (MX.X509Certificate cert) intermediateCerts = other.intermediateCerts.Clone (); } + public X509Certificate2ImplMono (byte[] rawData, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags) + { + switch (X509Certificate2.GetCertContentType (rawData)) { + case X509ContentType.Pkcs12: + _cert = ImportPkcs12 (rawData, password); + break; + + case X509ContentType.Cert: + case X509ContentType.Pkcs7: + _cert = new MX.X509Certificate (rawData); + break; + + default: + string msg = Locale.GetText ("Unable to decode certificate."); + throw new CryptographicException (msg); + } + } + public override X509CertificateImpl Clone () { ThrowIfContextInvalid (); @@ -105,28 +119,12 @@ MX.X509Certificate Cert { #region Implemented X509CertificateImpl members - public override string Issuer => MX.X501.ToString (Cert.GetIssuerName (), true, ", ", true); - - public override string Subject => MX.X501.ToString (Cert.GetSubjectName (), true, ", ", true); - - public override string LegacyIssuer => Cert.IssuerName; - - public override string LegacySubject => Cert.SubjectName; - - public override byte[] RawData => Cert.RawData; - - public override byte[] Thumbprint { - get { - ThrowIfContextInvalid (); - SHA1 sha = SHA1.Create (); - return sha.ComputeHash (_cert.RawData); - } + protected override byte[] GetRawCertData () + { + ThrowIfContextInvalid (); + return 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 @@ -134,21 +132,6 @@ public override bool Equals (X509CertificateImpl other, out bool result) return false; } - public override string KeyAlgorithm => Cert.KeyAlgorithm; - - public override byte[] KeyAlgorithmParameters => Cert.KeyAlgorithmParameters ?? throw new CryptographicException (); - - public override byte[] PublicKeyValue => Cert.PublicKey; - - public override byte[] SerialNumber { - get { - ThrowIfContextInvalid (); - var serial = Cert.SerialNumber; - Array.Reverse (serial); - return serial; - } - } - #endregion // constructors @@ -160,44 +143,11 @@ public X509Certificate2ImplMono () // properties - public override bool Archived { - get { - if (_cert == null) - throw new CryptographicException (empty_error); - return _archived; - } - set { - if (_cert == null) - throw new CryptographicException (empty_error); - _archived = value; - } - } - - public override X509ExtensionCollection Extensions { - get { - if (_cert == null) - throw new CryptographicException (empty_error); - if (_extensions == null) - _extensions = new X509ExtensionCollection (_cert); - return _extensions; - } - } - // FIXME - Could be more efficient public override bool HasPrivateKey { get { return PrivateKey != null; } } - public override X500DistinguishedName IssuerName { - get { - if (_cert == null) - throw new CryptographicException (empty_error); - if (issuer_name == null) - issuer_name = new X500DistinguishedName (_cert.GetIssuerName ().GetBytes ()); - return issuer_name; - } - } - public override AsymmetricAlgorithm PrivateKey { get { if (_cert == null) @@ -246,6 +196,16 @@ public override AsymmetricAlgorithm PrivateKey { } } + public override RSA GetRSAPrivateKey () + { + return PrivateKey as RSA; + } + + public override DSA GetDSAPrivateKey () + { + return PrivateKey as DSA; + } + public override PublicKey PublicKey { get { if (_cert == null) @@ -263,129 +223,8 @@ public override PublicKey PublicKey { } } - public override Oid SignatureAlgorithm { - get { - if (_cert == null) - throw new CryptographicException (empty_error); - - if (signature_algorithm == null) - signature_algorithm = new Oid (_cert.SignatureAlgorithm); - return signature_algorithm; - } - } - - public override X500DistinguishedName SubjectName { - get { - if (_cert == null) - throw new CryptographicException (empty_error); - - if (subject_name == null) - subject_name = new X500DistinguishedName (_cert.GetSubjectName ().GetBytes ()); - return subject_name; - } - } - - public override int Version { - get { - if (_cert == null) - throw new CryptographicException (empty_error); - return _cert.Version; - } - } - // methods - [MonoTODO ("always return String.Empty for UpnName, DnsFromAlternativeName and UrlName")] - public override string GetNameInfo (X509NameType nameType, bool forIssuer) - { - switch (nameType) { - case X509NameType.SimpleName: - if (_cert == null) - throw new CryptographicException (empty_error); - // return CN= or, if missing, the first part of the DN - ASN1 sn = forIssuer ? _cert.GetIssuerName () : _cert.GetSubjectName (); - ASN1 dn = Find (commonName, sn); - if (dn != null) - return GetValueAsString (dn); - if (sn.Count == 0) - return String.Empty; - ASN1 last_entry = sn[sn.Count - 1]; - if (last_entry.Count == 0) - return String.Empty; - return GetValueAsString (last_entry[0]); - case X509NameType.EmailName: - // return the E= part of the DN (if present) - ASN1 e = Find (email, forIssuer ? _cert.GetIssuerName () : _cert.GetSubjectName ()); - if (e != null) - return GetValueAsString (e); - return String.Empty; - case X509NameType.UpnName: - // FIXME - must find/create test case - return String.Empty; - case X509NameType.DnsName: - // return the CN= part of the DN (if present) - ASN1 cn = Find (commonName, forIssuer ? _cert.GetIssuerName () : _cert.GetSubjectName ()); - if (cn != null) - return GetValueAsString (cn); - return String.Empty; - case X509NameType.DnsFromAlternativeName: - // FIXME - must find/create test case - return String.Empty; - case X509NameType.UrlName: - // FIXME - must find/create test case - return String.Empty; - default: - throw new ArgumentException ("nameType"); - } - } - - static byte[] commonName = { 0x55, 0x04, 0x03 }; - static byte[] email = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01 }; - - private ASN1 Find (byte[] oid, ASN1 dn) - { - if (dn.Count == 0) - return null; - - // process SET - for (int i = 0; i < dn.Count; i++) { - ASN1 set = dn[i]; - for (int j = 0; j < set.Count; j++) { - ASN1 pair = set[j]; - if (pair.Count != 2) - continue; - - ASN1 poid = pair[0]; - if (poid == null) - continue; - - if (poid.CompareValue (oid)) - return pair; - } - } - return null; - } - - private string GetValueAsString (ASN1 pair) - { - if (pair.Count != 2) - return String.Empty; - - ASN1 value = pair[1]; - if ((value.Value == null) || (value.Length == 0)) - return String.Empty; - - if (value.Tag == 0x1E) { - // BMPSTRING - StringBuilder sb = new StringBuilder (); - for (int j = 1; j < value.Value.Length; j += 2) - sb.Append ((char)value.Value[j]); - return sb.ToString (); - } else { - return Encoding.UTF8.GetString (value.Value); - } - } - MX.X509Certificate ImportPkcs12 (byte[] rawData, SafePasswordHandle password) { if (password == null || password.IsInvalid) @@ -446,85 +285,10 @@ MX.X509Certificate ImportPkcs12 (byte[] rawData, string password) } } - [MonoTODO ("missing KeyStorageFlags support")] - public override void Import (byte[] rawData, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags) - { - Reset (); - - switch (X509Certificate2.GetCertContentType (rawData)) { - case X509ContentType.Pkcs12: - _cert = ImportPkcs12 (rawData, password); - break; - - case X509ContentType.Cert: - case X509ContentType.Pkcs7: - _cert = new MX.X509Certificate (rawData); - break; - - default: - string msg = Locale.GetText ("Unable to decode certificate."); - throw new CryptographicException (msg); - } - } - - [MonoTODO ("X509ContentType.SerializedCert is not supported")] - public override byte[] Export (X509ContentType contentType, SafePasswordHandle password) - { - if (_cert == null) - throw new CryptographicException (empty_error); - - switch (contentType) { - case X509ContentType.Cert: - return _cert.RawData; - case X509ContentType.Pfx: // this includes Pkcs12 - return ExportPkcs12 (password); - case X509ContentType.SerializedCert: - // TODO - throw new NotSupportedException (); - default: - string msg = Locale.GetText ("This certificate format '{0}' cannot be exported.", contentType); - throw new CryptographicException (msg); - } - } - - byte[] ExportPkcs12 (SafePasswordHandle password) - { - if (password == null || password.IsInvalid) - return ExportPkcs12 ((string)null); - var passwordString = password.Mono_DangerousGetString (); - return ExportPkcs12 (passwordString); - } - - byte[] ExportPkcs12 (string password) - { - var pfx = new MX.PKCS12 (); - try { - var attrs = new Hashtable (); - var localKeyId = new ArrayList (); - localKeyId.Add (new byte[] { 1, 0, 0, 0 }); - attrs.Add (MX.PKCS9.localKeyId, localKeyId); - - if (password != null) - pfx.Password = password; - pfx.AddCertificate (_cert, attrs); - var privateKey = PrivateKey; - if (privateKey != null) - pfx.AddPkcs8ShroudedKeyBag (privateKey, attrs); - return pfx.GetBytes (); - } finally { - pfx.Password = null; - } - } - public override void Reset () { _cert = null; - _archived = false; - _extensions = null; _publicKey = null; - issuer_name = null; - subject_name = null; - signature_algorithm = null; if (intermediateCerts != null) { intermediateCerts.Dispose (); intermediateCerts = null; diff --git a/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2ImplUnix.cs b/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2ImplUnix.cs new file mode 100644 index 000000000000..c4b14bcb1d4c --- /dev/null +++ b/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2ImplUnix.cs @@ -0,0 +1,259 @@ +// +// X509Certificate2ImplUnix.cs +// +// Authors: +// Martin Baulig +// +// Copyright (C) 2018 Xamarin, Inc. (http://www.xamarin.com) +// +// 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. +// +#if MONO_SECURITY_ALIAS +extern alias MonoSecurity; +#endif + +using System.Text; +using System.Diagnostics; +using System.Collections; +using System.Collections.Generic; +using Internal.Cryptography; +using Internal.Cryptography.Pal; +using Microsoft.Win32.SafeHandles; + +#if MONO_SECURITY_ALIAS +using MX = MonoSecurity::Mono.Security.X509; +#else +using MX = Mono.Security.X509; +#endif + +namespace System.Security.Cryptography.X509Certificates +{ + internal abstract class X509Certificate2ImplUnix : X509Certificate2Impl + { + bool readCertData; + CertificateData certData; + + void EnsureCertData () + { + if (readCertData) + return; + + ThrowIfContextInvalid (); + certData = new CertificateData (GetRawCertData ()); + readCertData = true; + } + + protected abstract byte[] GetRawCertData (); + + public sealed override bool Archived { + get { + return false; + } + set { + throw new PlatformNotSupportedException ( + SR.Format (SR.Cryptography_Unix_X509_PropertyNotSettable, nameof (Archived))); + } + } + + public sealed override string KeyAlgorithm { + get { + EnsureCertData (); + return certData.PublicKeyAlgorithm.AlgorithmId; + } + } + + public sealed override byte[] KeyAlgorithmParameters { + get { + EnsureCertData (); + return certData.PublicKeyAlgorithm.Parameters; + } + } + + public sealed override byte[] PublicKeyValue { + get { + EnsureCertData (); + return certData.PublicKey; + } + } + + public sealed override byte[] SerialNumber { + get { + EnsureCertData (); + return certData.SerialNumber; + } + } + + public sealed override string SignatureAlgorithm { + get { + EnsureCertData (); + return certData.SignatureAlgorithm.AlgorithmId; + } + } + + public sealed override string FriendlyName { + get { return ""; } + set { + throw new PlatformNotSupportedException ( + SR.Format (SR.Cryptography_Unix_X509_PropertyNotSettable, nameof (FriendlyName))); + } + } + + public sealed override int Version { + get { + EnsureCertData (); + return certData.Version + 1; + } + } + + public sealed override X500DistinguishedName SubjectName { + get { + EnsureCertData (); + return certData.Subject; + } + } + + public sealed override X500DistinguishedName IssuerName { + get { + EnsureCertData (); + return certData.Issuer; + } + } + + public sealed override string Subject => SubjectName.Name; + + public sealed override string Issuer => IssuerName.Name; + + public sealed override string LegacySubject => SubjectName.Decode (X500DistinguishedNameFlags.None); + + public sealed override string LegacyIssuer => IssuerName.Decode (X500DistinguishedNameFlags.None); + + public sealed override byte[] RawData { + get { + EnsureCertData (); + return certData.RawData; + } + } + + public sealed override byte[] Thumbprint { + get { + EnsureCertData (); + + using (SHA1 hash = SHA1.Create ()) { + return hash.ComputeHash (certData.RawData); + } + } + } + + public sealed override string GetNameInfo (X509NameType nameType, bool forIssuer) + { + EnsureCertData (); + return certData.GetNameInfo (nameType, forIssuer); + } + + public sealed override IEnumerable Extensions { + get { + EnsureCertData (); + return certData.Extensions; + } + } + + public sealed override DateTime NotAfter { + get { + EnsureCertData (); + return certData.NotAfter.ToLocalTime (); + } + } + + public sealed override DateTime NotBefore { + get { + EnsureCertData (); + return certData.NotBefore.ToLocalTime (); + } + } + + public sealed override void AppendPrivateKeyInfo (StringBuilder sb) + { + if (!HasPrivateKey) + return; + + // There's nothing really to say about the key, just acknowledge there is one. + sb.AppendLine (); + sb.AppendLine (); + sb.AppendLine ("[Private Key]"); + } + + public override void Reset () + { + readCertData = false; + } + + public sealed override byte[] Export (X509ContentType contentType, SafePasswordHandle password) + { + ThrowIfContextInvalid (); + + Debug.Assert (password != null); + switch (contentType) { + case X509ContentType.Cert: + return RawData; + case X509ContentType.Pkcs12: + return ExportPkcs12 (password); + case X509ContentType.Pkcs7: + return ExportPkcs12 ((string)null); + case X509ContentType.SerializedCert: + case X509ContentType.SerializedStore: + throw new PlatformNotSupportedException (SR.Cryptography_Unix_X509_SerializedExport); + default: + throw new CryptographicException (SR.Cryptography_X509_InvalidContentType); + } + } + + byte[] ExportPkcs12 (SafePasswordHandle password) + { + if (password == null || password.IsInvalid) + return ExportPkcs12 ((string)null); + var passwordString = password.Mono_DangerousGetString (); + return ExportPkcs12 (passwordString); + } + + byte[] ExportPkcs12 (string password) + { + var pfx = new MX.PKCS12 (); + try { + var attrs = new Hashtable (); + var localKeyId = new ArrayList (); + localKeyId.Add (new byte[] { 1, 0, 0, 0 }); + attrs.Add (MX.PKCS9.localKeyId, localKeyId); + if (password != null) + pfx.Password = password; + 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].RawData)); + } + var privateKey = PrivateKey; + if (privateKey != null) + pfx.AddPkcs8ShroudedKeyBag (privateKey, attrs); + return pfx.GetBytes (); + } finally { + pfx.Password = null; + } + } + } +} diff --git a/mcs/class/System/System.Security.Cryptography.X509Certificates/X509ChainImplMono.cs b/mcs/class/System/System.Security.Cryptography.X509Certificates/X509ChainImplMono.cs index bd4956996657..fcf990d4a254 100644 --- a/mcs/class/System/System.Security.Cryptography.X509Certificates/X509ChainImplMono.cs +++ b/mcs/class/System/System.Security.Cryptography.X509Certificates/X509ChainImplMono.cs @@ -521,12 +521,13 @@ private void Process (int n) { X509ChainElement element = elements [n]; X509Certificate2 certificate = element.Certificate; + var monoCertificate = X509Helper2.GetMonoCertificate (certificate); // pre-step: DSA certificates may inherit the parameters of their CA - if ((n != elements.Count - 1) && (certificate.MonoCertificate.KeyAlgorithm == "1.2.840.10040.4.1")) { - if (certificate.MonoCertificate.KeyAlgorithmParameters == null) { - X509Certificate2 parent = elements [n+1].Certificate; - certificate.MonoCertificate.KeyAlgorithmParameters = parent.MonoCertificate.KeyAlgorithmParameters; + if ((n != elements.Count - 1) && (monoCertificate.KeyAlgorithm == "1.2.840.10040.4.1")) { + if (monoCertificate.KeyAlgorithmParameters == null) { + var parent = X509Helper2.GetMonoCertificate (elements [n+1].Certificate); + monoCertificate.KeyAlgorithmParameters = parent.KeyAlgorithmParameters; } } @@ -703,7 +704,7 @@ private bool IsSignedWith (X509Certificate2 signed, AsymmetricAlgorithm pubkey) if (pubkey == null) return false; // Sadly X509Certificate2 doesn't expose the signature nor the tbs (to be signed) structure - var mx = signed.MonoCertificate; + var mx = X509Helper2.GetMonoCertificate (signed); return (mx.VerifySignature (pubkey)); } @@ -716,7 +717,8 @@ private string GetSubjectKeyIdentifier (X509Certificate2 certificate) // System.dll v2 doesn't have a class to deal with the AuthorityKeyIdentifier extension static string GetAuthorityKeyIdentifier (X509Certificate2 certificate) { - return GetAuthorityKeyIdentifier (certificate.MonoCertificate.Extensions ["2.5.29.35"]); + var monoCertificate = X509Helper2.GetMonoCertificate (certificate); + return GetAuthorityKeyIdentifier (monoCertificate.Extensions ["2.5.29.35"]); } // but anyway System.dll v2 doesn't expose CRL in any way so... @@ -853,7 +855,8 @@ private X509ChainStatusFlags CheckRevocation (X509Certificate2 certificate, X509 return X509ChainStatusFlags.RevocationStatusUnknown; } - MX.X509Crl.X509CrlEntry entry = crl.GetCrlEntry (certificate.MonoCertificate); + var monoCertificate = X509Helper2.GetMonoCertificate (certificate); + MX.X509Crl.X509CrlEntry entry = crl.GetCrlEntry (monoCertificate); if (entry != null) { // We have an entry for this CRL that includes an unknown CRITICAL extension // See [X.509 7.3] NOTE 4 diff --git a/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Helper2.cs b/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Helper2.cs index 7e7ecbb393dd..ecd7f2bb17f4 100644 --- a/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Helper2.cs +++ b/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Helper2.cs @@ -62,13 +62,7 @@ internal static MX.X509Certificate GetMonoCertificate (X509Certificate2 certific { if (certificate.Impl is X509Certificate2ImplMono monoImpl) return monoImpl.MonoCertificate; - if (certificate.Impl is X509Certificate2Impl impl2 && impl2.FallbackImpl is X509Certificate2ImplMono fallbackImpl) - return fallbackImpl.MonoCertificate; - - var impl = SystemDependencyProvider.Instance.CertificateProvider.Import (certificate, CertificateImportFlags.DisableNativeBackend); - if (impl is X509Certificate2ImplMono fallbackImpl2) - return fallbackImpl2.MonoCertificate; - throw new NotSupportedException (); + return new MX.X509Certificate (certificate.RawData); } internal static X509ChainImpl CreateChainImpl (bool useMachineContext) diff --git a/mcs/class/System/common.sources b/mcs/class/System/common.sources index 8796a9382fd8..126ae2895779 100644 --- a/mcs/class/System/common.sources +++ b/mcs/class/System/common.sources @@ -139,10 +139,15 @@ System.Security.Authentication.ExtendedProtection.Configuration/ExtendedProtecti System.Security.Authentication.ExtendedProtection.Configuration/ServiceNameElement.cs System.Security.Authentication.ExtendedProtection.Configuration/ServiceNameElementCollection.cs +../../../external/corefx/src/Common/src/System/Security/Cryptography/DerEncoder.cs +../../../external/corefx/src/Common/src/System/Security/Cryptography/DerSequenceReader.cs + System.Security.Cryptography/AsnEncodedData.cs ../../../external/corefx/src/System.Security.Cryptography.Encoding/src/System/Security/Cryptography/AsnEncodedDataCollection.cs ../../../external/corefx/src/System.Security.Cryptography.Encoding/src/System/Security/Cryptography/AsnEncodedDataEnumerator.cs +../../../external/corefx/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Oids.cs +../../../external/corefx/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.OSX/CertificateData.cs ../../../external/corefx/src/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/OpenFlags.cs System.Security.Cryptography.X509Certificates/OSX509Certificates.cs System.Security.Cryptography.X509Certificates/PublicKey.cs @@ -156,6 +161,7 @@ System.Security.Cryptography.X509Certificates/X509Certificate2Collection.cs System.Security.Cryptography.X509Certificates/X509Certificate2Enumerator.cs System.Security.Cryptography.X509Certificates/X509Certificate2Impl.cs System.Security.Cryptography.X509Certificates/X509Certificate2ImplMono.cs +System.Security.Cryptography.X509Certificates/X509Certificate2ImplUnix.cs System.Security.Cryptography.X509Certificates/X509CertificateCollection.cs System.Security.Cryptography.X509Certificates/X509CertificateImplCollection.cs System.Security.Cryptography.X509Certificates/X509Chain.cs diff --git a/mcs/class/corlib/System.Security.Cryptography.X509Certificates/X509CertificateImpl.cs b/mcs/class/corlib/System.Security.Cryptography.X509Certificates/X509CertificateImpl.cs index d3a2e73a9b60..2f9e2033fb19 100644 --- a/mcs/class/corlib/System.Security.Cryptography.X509Certificates/X509CertificateImpl.cs +++ b/mcs/class/corlib/System.Security.Cryptography.X509Certificates/X509CertificateImpl.cs @@ -113,6 +113,14 @@ public abstract byte[] SerialNumber { get; } + public abstract bool HasPrivateKey { + get; + } + + public abstract RSA GetRSAPrivateKey (); + + public abstract DSA GetDSAPrivateKey (); + public abstract byte[] Export (X509ContentType contentType, SafePasswordHandle password); public sealed override bool Equals (object obj) diff --git a/mcs/class/corlib/System.Security.Cryptography/CryptoConfig.cs b/mcs/class/corlib/System.Security.Cryptography/CryptoConfig.cs index 9b06caef3841..20fcc5684d5d 100644 --- a/mcs/class/corlib/System.Security.Cryptography/CryptoConfig.cs +++ b/mcs/class/corlib/System.Security.Cryptography/CryptoConfig.cs @@ -533,11 +533,6 @@ public static object CreateFromName (string name, params object[] args) } } - internal static string MapNameToOID (string name, OidGroup oidGroup) - { - return MapNameToOID (name); - } - public static string MapNameToOID (string name) { if (name == null) diff --git a/mcs/class/corlib/corlib.dll.sources b/mcs/class/corlib/corlib.dll.sources index b0eb2dbaabf7..03f55d12941d 100644 --- a/mcs/class/corlib/corlib.dll.sources +++ b/mcs/class/corlib/corlib.dll.sources @@ -1432,8 +1432,6 @@ ReferenceSources/AppContextDefaultValues.cs ../referencesource/mscorlib/system/security/cryptography/tripledescryptoserviceprovider.cs ../referencesource/mscorlib/system/security/cryptography/utils.cs -../referencesource/mscorlib/system/security/cryptography/x509certificates/x509utils.cs - ../../../external/corefx/src/System.Security.Claims/src/System/Security/Claims/GenericIdentity.cs ../referencesource/mscorlib/system/security/util/hex.cs diff --git a/mcs/class/referencesource/mscorlib/system/security/cryptography/dsasignaturedeformatter.cs b/mcs/class/referencesource/mscorlib/system/security/cryptography/dsasignaturedeformatter.cs index bf57d241caca..e2f7bf5db2be 100644 --- a/mcs/class/referencesource/mscorlib/system/security/cryptography/dsasignaturedeformatter.cs +++ b/mcs/class/referencesource/mscorlib/system/security/cryptography/dsasignaturedeformatter.cs @@ -26,7 +26,7 @@ public class DSASignatureDeformatter : AsymmetricSignatureDeformatter { public DSASignatureDeformatter() { // The hash algorithm is always SHA1 - _oid = CryptoConfig.MapNameToOID("SHA1", OidGroup.HashAlgorithm); + _oid = CryptoConfig.MapNameToOID("SHA1"); } public DSASignatureDeformatter(AsymmetricAlgorithm key) : this() { @@ -48,7 +48,7 @@ public override void SetKey(AsymmetricAlgorithm key) { } public override void SetHashAlgorithm(string strName) { - if (CryptoConfig.MapNameToOID(strName, OidGroup.HashAlgorithm) != _oid) + if (CryptoConfig.MapNameToOID(strName) != _oid) throw new CryptographicUnexpectedOperationException(Environment.GetResourceString("Cryptography_InvalidOperation")); } diff --git a/mcs/class/referencesource/mscorlib/system/security/cryptography/dsasignatureformatter.cs b/mcs/class/referencesource/mscorlib/system/security/cryptography/dsasignatureformatter.cs index 260113a9e12b..dd0a3ce7cffe 100644 --- a/mcs/class/referencesource/mscorlib/system/security/cryptography/dsasignatureformatter.cs +++ b/mcs/class/referencesource/mscorlib/system/security/cryptography/dsasignatureformatter.cs @@ -26,7 +26,7 @@ public class DSASignatureFormatter : AsymmetricSignatureFormatter { public DSASignatureFormatter() { // The hash algorithm is always SHA1 - _oid = CryptoConfig.MapNameToOID("SHA1", OidGroup.HashAlgorithm); + _oid = CryptoConfig.MapNameToOID("SHA1"); } public DSASignatureFormatter(AsymmetricAlgorithm key) : this() { @@ -48,7 +48,7 @@ public override void SetKey(AsymmetricAlgorithm key) { } public override void SetHashAlgorithm(String strName) { - if (CryptoConfig.MapNameToOID(strName, OidGroup.HashAlgorithm) != _oid) + if (CryptoConfig.MapNameToOID(strName) != _oid) throw new CryptographicUnexpectedOperationException(Environment.GetResourceString("Cryptography_InvalidOperation")); } From 7775a22a27c80bea11676ae781eb52dd56fbdeef Mon Sep 17 00:00:00 2001 From: Martin Baulig Date: Fri, 27 Jul 2018 02:29:43 -0400 Subject: [PATCH 2/4] Remove tests for broken / invalid certificates. --- .../X509CertificateTest.cs | 132 ------------------ 1 file changed, 132 deletions(-) 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 aa0f9e9a5afd..764f0b5a8e71 100644 --- a/mcs/class/corlib/Test/System.Security.Cryptography.X509Certificates/X509CertificateTest.cs +++ b/mcs/class/corlib/Test/System.Security.Cryptography.X509Certificates/X509CertificateTest.cs @@ -771,71 +771,6 @@ public void Certificate10 () } -// Certificate: basic\GTE.cer -// - X.509v1 self-signed certificate -// - md5RSA, RSA 1024 bits -// - Valid from/to doesn't include seconds! -[Test] -public void Certificate11 () -{ - // certificate can be loaded by constructor - byte[] cert = { 0x30,0x82,0x01,0xF5,0x30,0x82,0x01,0x5E,0x02,0x01,0x00,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x04,0x05,0x00,0x30,0x45,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x18,0x30,0x16,0x06,0x03,0x55,0x04,0x0A,0x13,0x0F,0x47,0x54,0x45,0x20,0x43,0x6F,0x72,0x70,0x6F,0x72,0x61,0x74,0x69,0x6F,0x6E,0x31,0x1C,0x30,0x1A,0x06,0x03,0x55,0x04,0x03,0x13,0x13,0x47,0x54,0x45,0x20,0x43,0x79,0x62,0x65,0x72,0x54,0x72,0x75,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x30,0x1A,0x17,0x0B, - 0x39,0x36,0x30,0x32,0x32,0x33,0x31,0x39,0x31,0x35,0x5A,0x17,0x0B,0x39,0x39,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x5A,0x30,0x45,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x18,0x30,0x16,0x06,0x03,0x55,0x04,0x0A,0x13,0x0F,0x47,0x54,0x45,0x20,0x43,0x6F,0x72,0x70,0x6F,0x72,0x61,0x74,0x69,0x6F,0x6E,0x31,0x1C,0x30,0x1A,0x06,0x03,0x55,0x04,0x03,0x13,0x13,0x47,0x54,0x45,0x20,0x43,0x79,0x62,0x65,0x72,0x54,0x72,0x75,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x30,0x81,0x9F,0x30,0x0D, - 0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8D,0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xB8,0xE6,0x4F,0xBA,0xDB,0x98,0x7C,0x71,0x7C,0xAF,0x44,0xB7,0xD3,0x0F,0x46,0xD9,0x64,0xE5,0x93,0xC1,0x42,0x8E,0xC7,0xBA,0x49,0x8D,0x35,0x2D,0x7A,0xE7,0x8B,0xBD,0xE5,0x05,0x31,0x59,0xC6,0xB1,0x2F,0x0A,0x0C,0xFB,0x9F,0xA7,0x3F,0xA2,0x09,0x66,0x84,0x56,0x1E,0x37,0x29,0x1B,0x87,0xE9,0x7E,0x0C,0xCA,0x9A,0x9F,0xA5,0x7F,0xF5,0x15,0x94,0xA3,0xD5,0xA2,0x46,0x82,0xD8,0x68,0x4C,0xD1,0x37, - 0x15,0x06,0x68,0xAF,0xBD,0xF8,0xB0,0xB3,0xF0,0x29,0xF5,0x95,0x5A,0x09,0x16,0x61,0x77,0x0A,0x22,0x25,0xD4,0x4F,0x45,0xAA,0xC7,0xBD,0xE5,0x96,0xDF,0xF9,0xD4,0xA8,0x8E,0x42,0xCC,0x24,0xC0,0x1E,0x91,0x27,0x4A,0xB5,0x6D,0x06,0x80,0x63,0x39,0xC4,0xA2,0x5E,0x38,0x03,0x02,0x03,0x01,0x00,0x01,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x04,0x05,0x00,0x03,0x81,0x81,0x00,0x34,0x9B,0x09,0x05,0x9D,0x42,0x48,0x7F,0x7C,0x24,0x8E,0xC2,0x88,0x65,0x78,0x6B,0x4D,0x2A,0x0E,0xAF,0xED,0xED,0xF0,0x6A, - 0x2D,0x37,0xEB,0x57,0x51,0x0E,0x8A,0xAD,0x2D,0x13,0x02,0xA1,0x40,0x6A,0x41,0xF6,0x69,0x72,0xBF,0x0F,0xA0,0x4E,0x55,0xE7,0x82,0xA6,0x57,0x91,0x8B,0x5D,0x43,0x08,0xC9,0xF8,0x71,0x07,0x82,0xE3,0x3E,0x14,0x01,0x24,0x0C,0x39,0xEB,0x61,0x22,0xF7,0xA2,0x0B,0x42,0x23,0x14,0xCA,0x10,0x18,0x36,0x0A,0x05,0xD1,0xC8,0x4A,0xF1,0x0E,0xB3,0xFD,0x00,0xD0,0xC6,0xEE,0x55,0xF2,0x4C,0x62,0xB4,0x19,0x73,0x1F,0x48,0x18,0xD8,0xB0,0x4E,0xB0,0x75,0xBC,0xB9,0x84,0x8B,0x1F,0x96,0x8A,0x83,0xF1,0xA0,0x1A,0xA2,0xED,0xFF,0x87, - 0x8C,0xA3,0x4F,0xA2 }; - - X509Certificate x509 = new X509Certificate (cert); - X509Certificate clone = new X509Certificate (x509); - - Assert.IsTrue (x509.Equals (clone), "Equals"); - Assert.IsTrue (clone.Equals (x509), "Equals"); - - FileStream fs = File.OpenWrite (temp_certificate_filename); - fs.Write (cert, 0, cert.Length); - fs.Close (); - - X509Certificate disk = X509Certificate.CreateFromCertFile (temp_certificate_filename); - Assert.IsTrue (disk.Equals (clone), "Equals"); - Assert.IsTrue (disk.Equals (x509), "Equals"); - byte[] hash = { 0xA2,0x75,0xE0,0x26,0xAC,0xD8,0x54,0x79,0x4A,0x4A,0xA2,0xCB,0x53,0xF6,0x62,0x33,0x12,0x9C,0x55,0xB6 }; - Assert.AreEqual (hash, x509.GetCertHash (), "GetCertHash"); - Assert.AreEqual ("A275E026ACD854794A4AA2CB53F66233129C55B6", x509.GetCertHashString (), "GetCertHashString"); - DateTime from = DateTime.ParseExact (x509.GetEffectiveDateString (), "MM/dd/yyyy HH:mm:ss", null).ToUniversalTime (); - Assert.AreEqual ("02/23/1996 19:15:00", from.ToString (), "GetEffectiveDateString"); - DateTime until = DateTime.ParseExact (x509.GetExpirationDateString (), "MM/dd/yyyy HH:mm:ss", null).ToUniversalTime (); - Assert.AreEqual ("12/31/1999 23:59:00", until.ToString (), "GetExpirationDateString"); - Assert.AreEqual ("X509", x509.GetFormat (), "GetFormat"); - Assert.AreEqual (-1569333210, x509.GetHashCode (), "GetHashCode"); - Assert.AreEqual ("C=US, O=GTE Corporation, CN=GTE CyberTrust Root", x509.GetIssuerName (), "GetIssuerName"); - Assert.AreEqual ("1.2.840.113549.1.1.1", x509.GetKeyAlgorithm (), "GetKeyAlgorithm"); - byte[] keyparams = { 0x05,0x00 }; - Assert.AreEqual (keyparams, x509.GetKeyAlgorithmParameters (), "GetKeyAlgorithmParameters"); - Assert.AreEqual ("0500", x509.GetKeyAlgorithmParametersString (), "GetKeyAlgorithmParametersString"); - Assert.AreEqual ("C=US, O=GTE Corporation, CN=GTE CyberTrust Root", x509.GetName (), "GetName"); - byte[] pubkey = { 0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xB8,0xE6,0x4F,0xBA,0xDB,0x98,0x7C,0x71,0x7C,0xAF,0x44,0xB7,0xD3,0x0F,0x46,0xD9,0x64,0xE5,0x93,0xC1,0x42,0x8E,0xC7,0xBA,0x49,0x8D,0x35,0x2D,0x7A,0xE7,0x8B,0xBD,0xE5,0x05,0x31,0x59,0xC6,0xB1,0x2F,0x0A,0x0C,0xFB,0x9F,0xA7,0x3F,0xA2,0x09,0x66,0x84,0x56,0x1E,0x37,0x29,0x1B,0x87,0xE9,0x7E,0x0C,0xCA,0x9A,0x9F,0xA5,0x7F,0xF5,0x15,0x94,0xA3,0xD5,0xA2,0x46,0x82,0xD8,0x68,0x4C,0xD1,0x37,0x15,0x06,0x68,0xAF,0xBD,0xF8,0xB0,0xB3,0xF0,0x29,0xF5,0x95,0x5A,0x09,0x16,0x61,0x77,0x0A, - 0x22,0x25,0xD4,0x4F,0x45,0xAA,0xC7,0xBD,0xE5,0x96,0xDF,0xF9,0xD4,0xA8,0x8E,0x42,0xCC,0x24,0xC0,0x1E,0x91,0x27,0x4A,0xB5,0x6D,0x06,0x80,0x63,0x39,0xC4,0xA2,0x5E,0x38,0x03,0x02,0x03,0x01,0x00,0x01 }; - Assert.AreEqual (pubkey, x509.GetPublicKey (), "GetPublicKey"); - Assert.AreEqual ("30818902818100B8E64FBADB987C717CAF44B7D30F46D964E593C1428EC7BA498D352D7AE78BBDE5053159C6B12F0A0CFB9FA73FA2096684561E37291B87E97E0CCA9A9FA57FF51594A3D5A24682D8684CD137150668AFBDF8B0B3F029F5955A091661770A2225D44F45AAC7BDE596DFF9D4A88E42CC24C01E91274AB56D06806339C4A25E38030203010001", x509.GetPublicKeyString (), "GetPublicKeyString"); - Assert.AreEqual (cert, x509.GetRawCertData (), "GetRawCertData"); - Assert.AreEqual (ToString (cert), x509.GetRawCertDataString (), "GetRawCertDataString"); - byte[] serial = { 0x00 }; - Assert.AreEqual (serial, x509.GetSerialNumber (), "GetSerialNumber"); - Assert.AreEqual ("00", x509.GetSerialNumberString (), "GetSerialNumberString"); - byte[] ToStringArray = { 0x43,0x45,0x52,0x54,0x49,0x46,0x49,0x43,0x41,0x54,0x45,0x3A,0x0D,0x0A,0x09,0x46,0x6F,0x72,0x6D,0x61,0x74,0x3A,0x20,0x20,0x58,0x35,0x30,0x39,0x0D,0x0A,0x09,0x4E,0x61,0x6D,0x65,0x3A,0x20,0x20,0x43,0x3D,0x55,0x53,0x2C,0x20,0x4F,0x3D,0x47,0x54,0x45,0x20,0x43,0x6F,0x72,0x70,0x6F,0x72,0x61,0x74,0x69,0x6F,0x6E,0x2C,0x20,0x43,0x4E,0x3D,0x47,0x54,0x45,0x20,0x43,0x79,0x62,0x65,0x72,0x54,0x72,0x75,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x0D,0x0A,0x09,0x49,0x73,0x73,0x75,0x69,0x6E,0x67,0x20,0x43,0x41,0x3A,0x20,0x20, - 0x43,0x3D,0x55,0x53,0x2C,0x20,0x4F,0x3D,0x47,0x54,0x45,0x20,0x43,0x6F,0x72,0x70,0x6F,0x72,0x61,0x74,0x69,0x6F,0x6E,0x2C,0x20,0x43,0x4E,0x3D,0x47,0x54,0x45,0x20,0x43,0x79,0x62,0x65,0x72,0x54,0x72,0x75,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x0D,0x0A,0x09,0x4B,0x65,0x79,0x20,0x41,0x6C,0x67,0x6F,0x72,0x69,0x74,0x68,0x6D,0x3A,0x20,0x20,0x31,0x2E,0x32,0x2E,0x38,0x34,0x30,0x2E,0x31,0x31,0x33,0x35,0x34,0x39,0x2E,0x31,0x2E,0x31,0x2E,0x31,0x0D,0x0A,0x09,0x53,0x65,0x72,0x69,0x61,0x6C,0x20,0x4E,0x75,0x6D,0x62, - 0x65,0x72,0x3A,0x20,0x20,0x30,0x30,0x0D,0x0A,0x09,0x4B,0x65,0x79,0x20,0x41,0x6C,0x6F,0x67,0x72,0x69,0x74,0x68,0x6D,0x20,0x50,0x61,0x72,0x61,0x6D,0x65,0x74,0x65,0x72,0x73,0x3A,0x20,0x20,0x30,0x35,0x30,0x30,0x0D,0x0A,0x09,0x50,0x75,0x62,0x6C,0x69,0x63,0x20,0x4B,0x65,0x79,0x3A,0x20,0x20,0x33,0x30,0x38,0x31,0x38,0x39,0x30,0x32,0x38,0x31,0x38,0x31,0x30,0x30,0x42,0x38,0x45,0x36,0x34,0x46,0x42,0x41,0x44,0x42,0x39,0x38,0x37,0x43,0x37,0x31,0x37,0x43,0x41,0x46,0x34,0x34,0x42,0x37,0x44,0x33,0x30,0x46,0x34, - 0x36,0x44,0x39,0x36,0x34,0x45,0x35,0x39,0x33,0x43,0x31,0x34,0x32,0x38,0x45,0x43,0x37,0x42,0x41,0x34,0x39,0x38,0x44,0x33,0x35,0x32,0x44,0x37,0x41,0x45,0x37,0x38,0x42,0x42,0x44,0x45,0x35,0x30,0x35,0x33,0x31,0x35,0x39,0x43,0x36,0x42,0x31,0x32,0x46,0x30,0x41,0x30,0x43,0x46,0x42,0x39,0x46,0x41,0x37,0x33,0x46,0x41,0x32,0x30,0x39,0x36,0x36,0x38,0x34,0x35,0x36,0x31,0x45,0x33,0x37,0x32,0x39,0x31,0x42,0x38,0x37,0x45,0x39,0x37,0x45,0x30,0x43,0x43,0x41,0x39,0x41,0x39,0x46,0x41,0x35,0x37,0x46,0x46,0x35,0x31, - 0x35,0x39,0x34,0x41,0x33,0x44,0x35,0x41,0x32,0x34,0x36,0x38,0x32,0x44,0x38,0x36,0x38,0x34,0x43,0x44,0x31,0x33,0x37,0x31,0x35,0x30,0x36,0x36,0x38,0x41,0x46,0x42,0x44,0x46,0x38,0x42,0x30,0x42,0x33,0x46,0x30,0x32,0x39,0x46,0x35,0x39,0x35,0x35,0x41,0x30,0x39,0x31,0x36,0x36,0x31,0x37,0x37,0x30,0x41,0x32,0x32,0x32,0x35,0x44,0x34,0x34,0x46,0x34,0x35,0x41,0x41,0x43,0x37,0x42,0x44,0x45,0x35,0x39,0x36,0x44,0x46,0x46,0x39,0x44,0x34,0x41,0x38,0x38,0x45,0x34,0x32,0x43,0x43,0x32,0x34,0x43,0x30,0x31,0x45,0x39, - 0x31,0x32,0x37,0x34,0x41,0x42,0x35,0x36,0x44,0x30,0x36,0x38,0x30,0x36,0x33,0x33,0x39,0x43,0x34,0x41,0x32,0x35,0x45,0x33,0x38,0x30,0x33,0x30,0x32,0x30,0x33,0x30,0x31,0x30,0x30,0x30,0x31,0x0D,0x0A,0x0D,0x0A }; - string tsa = Encoding.Default.GetString (ToStringArray).Replace ("\r\n", Environment.NewLine); - //Assert.AreEqual (tsa, x509.ToString (true), "ToString(true)"); - Assert.AreEqual ("CN=GTE CyberTrust Root, O=GTE Corporation, C=US", x509.Issuer, "Issuer"); - Assert.AreEqual ("CN=GTE CyberTrust Root, O=GTE Corporation, C=US", x509.Subject, "Subject"); -} - - // Certificate: basic\ms_spc.cer // no comments [Test] @@ -910,73 +845,6 @@ public void Certificate12 () Assert.AreEqual ("CN=Microsoft Corporation, OU=Copyright (c) 2002 Microsoft Corp., O=Microsoft Corporation, L=Redmond, S=Washington, C=US", x509.Subject, "Subject"); } - -// Certificate: basic\DSAParametersInheritedCACert.cer -// - X.509v3 end-entity certificate -// - sha1DSA, DSA 1024 bits -// - has NO parameters (shared group is present in issuer certificate) -// !!! MS bugs when using constructor X509Certificate(X509Certificate) !!! -[Test] -[ExpectedException (typeof (CryptographicException))] -public void Certificate13 () -{ - // certificate can be loaded by constructor - byte[] cert = { 0x30,0x82,0x02,0x14,0x30,0x82,0x01,0xD3,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x02,0x30,0x09,0x06,0x07,0x2A,0x86,0x48,0xCE,0x38,0x04,0x03,0x30,0x3A,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x1A,0x30,0x18,0x06,0x03,0x55,0x04,0x0A,0x13,0x11,0x54,0x65,0x73,0x74,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x73,0x31,0x0F,0x30,0x0D,0x06,0x03,0x55,0x04,0x03,0x13,0x06,0x44,0x53,0x41,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x30,0x31,0x30,0x34,0x31,0x39,0x31,0x34,0x35,0x37, - 0x32,0x30,0x5A,0x17,0x0D,0x31,0x31,0x30,0x34,0x31,0x39,0x31,0x34,0x35,0x37,0x32,0x30,0x5A,0x30,0x4F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x1A,0x30,0x18,0x06,0x03,0x55,0x04,0x0A,0x13,0x11,0x54,0x65,0x73,0x74,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x73,0x31,0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x03,0x13,0x1B,0x44,0x53,0x41,0x20,0x50,0x61,0x72,0x61,0x6D,0x65,0x74,0x65,0x72,0x73,0x20,0x49,0x6E,0x68,0x65,0x72,0x69,0x74,0x65,0x64,0x20,0x43,0x41,0x30, - 0x81,0x92,0x30,0x09,0x06,0x07,0x2A,0x86,0x48,0xCE,0x38,0x04,0x01,0x03,0x81,0x84,0x00,0x02,0x81,0x80,0x67,0x8C,0x47,0xDA,0x0C,0x36,0x81,0x64,0x39,0xF8,0x1A,0x37,0x0B,0xF0,0xBB,0xD4,0x13,0xFD,0x67,0x3D,0x40,0xC8,0x9C,0x92,0xE1,0x3A,0x89,0x54,0xB0,0xF2,0x97,0xA5,0x70,0xD0,0x64,0x17,0xA4,0xA7,0x7C,0xA9,0xE9,0x27,0x09,0x65,0xDF,0xA0,0xA5,0x1C,0xFC,0x04,0xDA,0x3E,0xDD,0x62,0x6B,0xF0,0x0C,0xED,0x81,0x57,0x4F,0x5D,0x29,0xC8,0x08,0x59,0x19,0x0C,0x5F,0x8D,0x88,0xF0,0xFF,0x8C,0xB6,0xE8,0x75,0x01,0xBE,0x10, - 0x0A,0x64,0xDF,0x57,0x7B,0x8B,0x6C,0x56,0xF0,0x53,0xCE,0x43,0x88,0xB9,0x09,0x99,0x08,0x3C,0x90,0xAF,0x01,0xE8,0xD9,0x32,0x5D,0xED,0x56,0x02,0xCF,0x60,0xD2,0x01,0x3A,0xE3,0x0A,0x2B,0x9E,0x91,0x41,0xF6,0xC7,0x7C,0xDE,0x6C,0x99,0x63,0x00,0x0E,0xA3,0x7C,0x30,0x7A,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x5D,0x24,0xEE,0x8A,0x55,0x1A,0xF2,0xC6,0xC9,0xB2,0xC2,0xBF,0x8A,0xF0,0xB2,0x49,0x4F,0x3A,0xB3,0x1B,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x74,0x15,0xD5,0x24, - 0x1C,0xBD,0x5E,0x65,0x88,0x1F,0xE1,0x8B,0x09,0x7E,0x7F,0xEA,0x19,0x48,0x4E,0x61,0x30,0x17,0x06,0x03,0x55,0x1D,0x20,0x04,0x10,0x30,0x0E,0x30,0x0C,0x06,0x0A,0x60,0x86,0x48,0x01,0x65,0x03,0x02,0x01,0x30,0x01,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x09,0x06,0x07,0x2A,0x86,0x48,0xCE,0x38,0x04,0x03,0x03,0x30,0x00,0x30,0x2D,0x02,0x15,0x00,0xA8,0x59,0x6F,0x31,0x77,0xB6,0x20, - 0xEC,0x36,0x9B,0xEB,0x4B,0x61,0x0A,0xAF,0x44,0xED,0x72,0xBA,0x29,0x02,0x14,0x6D,0x22,0xE1,0xBD,0x4D,0x27,0xF6,0x2E,0x3B,0x1F,0xD7,0x9D,0xD6,0x59,0x5E,0xCB,0x25,0x86,0x22,0xD8 }; - - X509Certificate x509 = new X509Certificate (cert); -// X509Certificate clone = new X509Certificate (x509); - -// Assert.IsTrue (x509.Equals (clone), "Equals"); -// Assert.IsTrue (clone.Equals (x509), "Equals"); - - FileStream fs = File.OpenWrite (temp_certificate_filename); - fs.Write (cert, 0, cert.Length); - fs.Close (); - - X509Certificate disk = X509Certificate.CreateFromCertFile (temp_certificate_filename); -// Assert.IsTrue (disk.Equals (clone), "Equals"); - Assert.IsTrue (disk.Equals (x509), "Equals"); - byte[] hash = { 0x0E,0x29,0xCD,0xDC,0xA5,0xE7,0x32,0xA2,0x0D,0xCE,0xD8,0x7B,0x3D,0x00,0x24,0x46,0x85,0x3E,0xBB,0xD1 }; - Assert.AreEqual (hash, x509.GetCertHash (), "GetCertHash"); - Assert.AreEqual ("0E29CDDCA5E732A20DCED87B3D002446853EBBD1", x509.GetCertHashString (), "GetCertHashString"); - DateTime from = DateTime.ParseExact (x509.GetEffectiveDateString (), "MM/dd/yyyy HH:mm:ss", null).ToUniversalTime (); - Assert.AreEqual ("04/19/2001 14:57:20", from.ToString (), "GetEffectiveDateString"); - DateTime until = DateTime.ParseExact (x509.GetExpirationDateString (), "MM/dd/yyyy HH:mm:ss", null).ToUniversalTime (); - Assert.AreEqual ("04/19/2011 14:57:20", until.ToString (), "GetExpirationDateString"); - Assert.AreEqual ("X509", x509.GetFormat (), "GetFormat"); - Assert.AreEqual (237620700, x509.GetHashCode (), "GetHashCode"); - Assert.AreEqual ("C=US, O=Test Certificates, CN=DSA CA", x509.GetIssuerName (), "GetIssuerName"); - Assert.AreEqual ("1.2.840.10040.4.1", x509.GetKeyAlgorithm (), "GetKeyAlgorithm"); - // this fails under 2.0 - Assert.IsNull (x509.GetKeyAlgorithmParameters (), "GetKeyAlgorithmParameters"); - Assert.IsNull (x509.GetKeyAlgorithmParametersString (), "GetKeyAlgorithmParametersString"); - Assert.AreEqual ("C=US, O=Test Certificates, CN=DSA Parameters Inherited CA", x509.GetName (), "GetName"); - byte[] pubkey = { 0x02,0x81,0x80,0x67,0x8C,0x47,0xDA,0x0C,0x36,0x81,0x64,0x39,0xF8,0x1A,0x37,0x0B,0xF0,0xBB,0xD4,0x13,0xFD,0x67,0x3D,0x40,0xC8,0x9C,0x92,0xE1,0x3A,0x89,0x54,0xB0,0xF2,0x97,0xA5,0x70,0xD0,0x64,0x17,0xA4,0xA7,0x7C,0xA9,0xE9,0x27,0x09,0x65,0xDF,0xA0,0xA5,0x1C,0xFC,0x04,0xDA,0x3E,0xDD,0x62,0x6B,0xF0,0x0C,0xED,0x81,0x57,0x4F,0x5D,0x29,0xC8,0x08,0x59,0x19,0x0C,0x5F,0x8D,0x88,0xF0,0xFF,0x8C,0xB6,0xE8,0x75,0x01,0xBE,0x10,0x0A,0x64,0xDF,0x57,0x7B,0x8B,0x6C,0x56,0xF0,0x53,0xCE,0x43,0x88,0xB9,0x09,0x99,0x08,0x3C, - 0x90,0xAF,0x01,0xE8,0xD9,0x32,0x5D,0xED,0x56,0x02,0xCF,0x60,0xD2,0x01,0x3A,0xE3,0x0A,0x2B,0x9E,0x91,0x41,0xF6,0xC7,0x7C,0xDE,0x6C,0x99,0x63,0x00,0x0E }; - Assert.AreEqual (pubkey, x509.GetPublicKey (), "GetPublicKey"); - Assert.AreEqual ("028180678C47DA0C36816439F81A370BF0BBD413FD673D40C89C92E13A8954B0F297A570D06417A4A77CA9E9270965DFA0A51CFC04DA3EDD626BF00CED81574F5D29C80859190C5F8D88F0FF8CB6E87501BE100A64DF577B8B6C56F053CE4388B90999083C90AF01E8D9325DED5602CF60D2013AE30A2B9E9141F6C77CDE6C9963000E", x509.GetPublicKeyString (), "GetPublicKeyString"); - Assert.AreEqual (cert, x509.GetRawCertData (), "GetRawCertData"); - Assert.AreEqual (ToString (cert), x509.GetRawCertDataString (), "GetRawCertDataString"); - byte[] serial = { 0x02 }; - Assert.AreEqual (serial, x509.GetSerialNumber (), "GetSerialNumber"); - Assert.AreEqual ("02", x509.GetSerialNumberString (), "GetSerialNumberString"); - byte[] ToStringArray = { 0x43,0x45,0x52,0x54,0x49,0x46,0x49,0x43,0x41,0x54,0x45,0x3A,0x0D,0x0A,0x09,0x46,0x6F,0x72,0x6D,0x61,0x74,0x3A,0x20,0x20,0x58,0x35,0x30,0x39,0x0D,0x0A,0x09,0x4E,0x61,0x6D,0x65,0x3A,0x20,0x20,0x43,0x3D,0x55,0x53,0x2C,0x20,0x4F,0x3D,0x54,0x65,0x73,0x74,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x73,0x2C,0x20,0x43,0x4E,0x3D,0x44,0x53,0x41,0x20,0x50,0x61,0x72,0x61,0x6D,0x65,0x74,0x65,0x72,0x73,0x20,0x49,0x6E,0x68,0x65,0x72,0x69,0x74,0x65,0x64,0x20,0x43,0x41,0x0D,0x0A,0x09,0x49,0x73,0x73, - 0x75,0x69,0x6E,0x67,0x20,0x43,0x41,0x3A,0x20,0x20,0x43,0x3D,0x55,0x53,0x2C,0x20,0x4F,0x3D,0x54,0x65,0x73,0x74,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x73,0x2C,0x20,0x43,0x4E,0x3D,0x44,0x53,0x41,0x20,0x43,0x41,0x0D,0x0A,0x09,0x4B,0x65,0x79,0x20,0x41,0x6C,0x67,0x6F,0x72,0x69,0x74,0x68,0x6D,0x3A,0x20,0x20,0x31,0x2E,0x32,0x2E,0x38,0x34,0x30,0x2E,0x31,0x30,0x30,0x34,0x30,0x2E,0x34,0x2E,0x31,0x0D,0x0A,0x09,0x53,0x65,0x72,0x69,0x61,0x6C,0x20,0x4E,0x75,0x6D,0x62,0x65,0x72,0x3A,0x20, - 0x20,0x30,0x32,0x0D,0x0A,0x09,0x50,0x75,0x62,0x6C,0x69,0x63,0x20,0x4B,0x65,0x79,0x3A,0x20,0x20,0x30,0x32,0x38,0x31,0x38,0x30,0x36,0x37,0x38,0x43,0x34,0x37,0x44,0x41,0x30,0x43,0x33,0x36,0x38,0x31,0x36,0x34,0x33,0x39,0x46,0x38,0x31,0x41,0x33,0x37,0x30,0x42,0x46,0x30,0x42,0x42,0x44,0x34,0x31,0x33,0x46,0x44,0x36,0x37,0x33,0x44,0x34,0x30,0x43,0x38,0x39,0x43,0x39,0x32,0x45,0x31,0x33,0x41,0x38,0x39,0x35,0x34,0x42,0x30,0x46,0x32,0x39,0x37,0x41,0x35,0x37,0x30,0x44,0x30,0x36,0x34,0x31,0x37,0x41,0x34,0x41, - 0x37,0x37,0x43,0x41,0x39,0x45,0x39,0x32,0x37,0x30,0x39,0x36,0x35,0x44,0x46,0x41,0x30,0x41,0x35,0x31,0x43,0x46,0x43,0x30,0x34,0x44,0x41,0x33,0x45,0x44,0x44,0x36,0x32,0x36,0x42,0x46,0x30,0x30,0x43,0x45,0x44,0x38,0x31,0x35,0x37,0x34,0x46,0x35,0x44,0x32,0x39,0x43,0x38,0x30,0x38,0x35,0x39,0x31,0x39,0x30,0x43,0x35,0x46,0x38,0x44,0x38,0x38,0x46,0x30,0x46,0x46,0x38,0x43,0x42,0x36,0x45,0x38,0x37,0x35,0x30,0x31,0x42,0x45,0x31,0x30,0x30,0x41,0x36,0x34,0x44,0x46,0x35,0x37,0x37,0x42,0x38,0x42,0x36,0x43,0x35, - 0x36,0x46,0x30,0x35,0x33,0x43,0x45,0x34,0x33,0x38,0x38,0x42,0x39,0x30,0x39,0x39,0x39,0x30,0x38,0x33,0x43,0x39,0x30,0x41,0x46,0x30,0x31,0x45,0x38,0x44,0x39,0x33,0x32,0x35,0x44,0x45,0x44,0x35,0x36,0x30,0x32,0x43,0x46,0x36,0x30,0x44,0x32,0x30,0x31,0x33,0x41,0x45,0x33,0x30,0x41,0x32,0x42,0x39,0x45,0x39,0x31,0x34,0x31,0x46,0x36,0x43,0x37,0x37,0x43,0x44,0x45,0x36,0x43,0x39,0x39,0x36,0x33,0x30,0x30,0x30,0x45,0x0D,0x0A,0x0D,0x0A }; - string tsa = Encoding.Default.GetString (ToStringArray).Replace ("\r\n", Environment.NewLine); - //Assert.AreEqual (tsa, x509.ToString (true), "ToString(true)"); - Assert.AreEqual ("C=US, O=\"RSA Data Security, Inc.\", OU=Secure Server Certification Authority", x509.Issuer, "Issuer"); - Assert.AreEqual ("C=US, S=California, O=CommerceNet, OU=Server Certification Authority", x509.Subject, "Subject"); -} - - // Number of certificates: 12 // Number of invalid certificates: 1 } From 5ab7c93e42b1717d31e4e4523822d9e66a552c91 Mon Sep 17 00:00:00 2001 From: monojenkins Date: Mon, 19 Nov 2018 23:58:14 +0000 Subject: [PATCH 3/4] [csproj] Update project files --- mcs/class/System/System.csproj | 90 ++++++++++++++++++++++++++++++++++ mcs/class/corlib/corlib.csproj | 1 - 2 files changed, 90 insertions(+), 1 deletion(-) diff --git a/mcs/class/System/System.csproj b/mcs/class/System/System.csproj index 17a5b2be349e..b282c0b3614f 100644 --- a/mcs/class/System/System.csproj +++ b/mcs/class/System/System.csproj @@ -146,6 +146,8 @@ + + @@ -468,6 +470,8 @@ + + @@ -962,6 +966,7 @@ + @@ -3908,6 +3913,11 @@ ./../../../external/binary-reference-assemblies/v4.7.1/System.Core.dll False + + False + ./../../../external/binary-reference-assemblies/v4.7.1/System.Numerics.dll + False + False ./../../../external/binary-reference-assemblies/v4.7.1/System.Configuration.dll @@ -3933,6 +3943,11 @@ ./../../../external/binary-reference-assemblies/build/monodroid/System.Core.dll False + + False + ./../../../external/binary-reference-assemblies/build/monodroid/System.Numerics.dll + False + MonoSecurity @@ -3953,6 +3968,11 @@ ./../../../external/binary-reference-assemblies/build/monotouch/System.Core.dll False + + False + ./../../../external/binary-reference-assemblies/build/monotouch/System.Numerics.dll + False + MonoSecurity @@ -3973,6 +3993,11 @@ ./../../../external/binary-reference-assemblies/build/monotouch/System.Core.dll False + + False + ./../../../external/binary-reference-assemblies/build/monotouch/System.Numerics.dll + False + MonoSecurity @@ -3993,6 +4018,11 @@ ./../../../external/binary-reference-assemblies/build/monotouch/System.Core.dll False + + False + ./../../../external/binary-reference-assemblies/build/monotouch/System.Numerics.dll + False + @@ -4010,6 +4040,11 @@ ./../../../external/binary-reference-assemblies/build/monotouch/System.Core.dll False + + False + ./../../../external/binary-reference-assemblies/build/monotouch/System.Numerics.dll + False + @@ -4027,6 +4062,11 @@ ./../../../external/binary-reference-assemblies/build/monotouch/System.Core.dll False + + False + ./../../../external/binary-reference-assemblies/build/monotouch/System.Numerics.dll + False + MonoSecurity @@ -4047,6 +4087,11 @@ ./../../../external/binary-reference-assemblies/build/monotouch/System.Core.dll False + + False + ./../../../external/binary-reference-assemblies/build/monotouch/System.Numerics.dll + False + MonoSecurity @@ -4071,6 +4116,11 @@ ./../../../external/binary-reference-assemblies/build/monotouch/System.Core.dll False + + False + ./../../../external/binary-reference-assemblies/build/monotouch/System.Numerics.dll + False + MonoSecurity @@ -4095,6 +4145,11 @@ ./../../../external/binary-reference-assemblies/build/monotouch/System.Core.dll False + + False + ./../../../external/binary-reference-assemblies/build/monotouch/System.Numerics.dll + False + MonoSecurity @@ -4119,6 +4174,11 @@ ./../../../external/binary-reference-assemblies/build/monotouch/System.Core.dll False + + False + ./../../../external/binary-reference-assemblies/build/monotouch/System.Numerics.dll + False + MonoSecurity @@ -4139,6 +4199,11 @@ ./../../../external/binary-reference-assemblies/build/monotouch/System.Core.dll False + + False + ./../../../external/binary-reference-assemblies/build/monotouch/System.Numerics.dll + False + MonoSecurity @@ -4159,6 +4224,11 @@ ./../../../external/binary-reference-assemblies/build/monotouch/System.Core.dll False + + False + ./../../../external/binary-reference-assemblies/build/monotouch/System.Numerics.dll + False + MonoSecurity @@ -4179,6 +4249,11 @@ ./../../../external/binary-reference-assemblies/v4.7.1/System.Core.dll False + + False + ./../../../external/binary-reference-assemblies/v4.7.1/System.Numerics.dll + False + False ./../../../external/binary-reference-assemblies/v4.7.1/System.Configuration.dll @@ -4204,6 +4279,11 @@ ./../../../external/binary-reference-assemblies/build/monotouch/System.Core.dll False + + False + ./../../../external/binary-reference-assemblies/build/monotouch/System.Numerics.dll + False + MonoSecurity @@ -4224,6 +4304,11 @@ ./../../../external/binary-reference-assemblies/build/monotouch/System.Core.dll False + + False + ./../../../external/binary-reference-assemblies/build/monotouch/System.Numerics.dll + False + MonoSecurity @@ -4244,6 +4329,11 @@ ./../../../external/binary-reference-assemblies/build/monotouch/System.Core.dll False + + False + ./../../../external/binary-reference-assemblies/build/monotouch/System.Numerics.dll + False + MonoSecurity diff --git a/mcs/class/corlib/corlib.csproj b/mcs/class/corlib/corlib.csproj index 6b4b6e406d37..6720f5beb0da 100644 --- a/mcs/class/corlib/corlib.csproj +++ b/mcs/class/corlib/corlib.csproj @@ -1216,7 +1216,6 @@ - From 29e147564f42869f9bb987ecce38b12c172f684c Mon Sep 17 00:00:00 2001 From: monojenkins Date: Thu, 29 Nov 2018 20:18:12 +0000 Subject: [PATCH 4/4] Bump API snapshot submodule --- external/api-snapshot | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/api-snapshot b/external/api-snapshot index 1cde6f37de2c..afe9c87a3384 160000 --- a/external/api-snapshot +++ b/external/api-snapshot @@ -1 +1 @@ -Subproject commit 1cde6f37de2c72e2a59738f04243c37be55edc68 +Subproject commit afe9c87a33844d92db077a77a5c2b91a06df8645