From c76ac565499f3e7c657126d46c00b67a0d74832c Mon Sep 17 00:00:00 2001 From: Krzysztof Wicher Date: Fri, 19 May 2023 20:24:57 +0000 Subject: [PATCH] Merged PR 30724: [6.0] Apply iteration work limits to X509 certificate loading Block password-less PKCS12 blobs on X509 certificate loadings/imports and prevent AIA fetching of non-cert types. --- .../Security/Cryptography/KdfWorkLimiter.cs | 86 ++ .../Cryptography/PasswordBasedEncryption.cs | 1 + .../System/Security/Cryptography/Pkcs12Kdf.cs | 1 + .../tests/System/Net/Http/TestHelper.cs | 2 +- .../X509Certificates/RevocationResponder.cs | 49 +- .../SslStreamStreamToStreamTest.cs | 2 +- .../tests/FunctionalTests/TestHelper.cs | 2 +- ...em.Security.Cryptography.Algorithms.csproj | 4 +- .../System.Security.Cryptography.Cng.csproj | 2 + .../System.Security.Cryptography.Pkcs.csproj | 8 +- .../Pal.Android/AndroidCertificatePal.cs | 11 +- .../Cryptography/Pal.Android/StorePal.cs | 10 +- .../AppleCertificatePal.ImportExport.cs | 10 + .../Pal.OSX/AppleCertificatePal.cs | 2 +- .../Internal/Cryptography/Pal.OSX/StorePal.cs | 8 +- .../Pal.Unix/CertificateAssetDownloader.cs | 10 + .../Pal.Unix/OpenSslX509CertificateReader.cs | 3 +- .../Cryptography/Pal.Unix/PkcsFormatReader.cs | 11 +- .../Cryptography/Pal.Unix/StorePal.cs | 4 +- .../Pal.Windows/CertificatePal.Import.cs | 7 + .../Pal.Windows/StorePal.Import.cs | 6 + .../AppleCertificatePal.ImportExport.cs | 15 +- .../Pal.iOS/AppleCertificatePal.Pkcs12.cs | 2 +- .../Internal/Cryptography/Pal.iOS/StorePal.cs | 12 +- .../Win32/SafeHandles/SafePasswordHandle.cs | 20 +- .../src/Resources/Strings.resx | 5 +- ...urity.Cryptography.X509Certificates.csproj | 214 +-- .../X509Certificates/Asn1/PfxAsn.manual.cs | 258 ++++ .../LocalAppContextSwitches.cs | 31 + .../X509Certificates/X509Certificate.cs | 103 +- .../X509Certificate2Collection.cs | 29 +- .../tests/CertTests.cs | 2 +- .../tests/CollectionImportTests.cs | 2 +- .../tests/CollectionTests.cs | 8 +- .../tests/ExportTests.cs | 4 +- ...tionCountTests.CustomAppDomainDataLimit.cs | 139 ++ .../PfxIterationCountTests.X509Certificate.cs | 26 + ...PfxIterationCountTests.X509Certificate2.cs | 26 + ...onCountTests.X509Certificate2Collection.cs | 44 + .../tests/PfxIterationCountTests.cs | 203 +++ .../tests/PfxTests.cs | 75 + .../tests/RevocationTests/AiaTests.cs | 35 + ...Cryptography.X509Certificates.Tests.csproj | 5 + .../tests/TempFileHolder.cs | 7 + .../tests/TestData.cs | 1216 +++++++++++++++++ 45 files changed, 2561 insertions(+), 159 deletions(-) create mode 100644 src/libraries/Common/src/System/Security/Cryptography/KdfWorkLimiter.cs create mode 100644 src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/PfxAsn.manual.cs create mode 100644 src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/LocalAppContextSwitches.cs create mode 100644 src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxIterationCountTests.CustomAppDomainDataLimit.cs create mode 100644 src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxIterationCountTests.X509Certificate.cs create mode 100644 src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxIterationCountTests.X509Certificate2.cs create mode 100644 src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxIterationCountTests.X509Certificate2Collection.cs create mode 100644 src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxIterationCountTests.cs diff --git a/src/libraries/Common/src/System/Security/Cryptography/KdfWorkLimiter.cs b/src/libraries/Common/src/System/Security/Cryptography/KdfWorkLimiter.cs new file mode 100644 index 00000000000..7500212fe27 --- /dev/null +++ b/src/libraries/Common/src/System/Security/Cryptography/KdfWorkLimiter.cs @@ -0,0 +1,86 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; + +namespace System.Security.Cryptography +{ + // Places KDF work limits on the current thread. + internal static class KdfWorkLimiter + { + [ThreadStatic] + private static State? t_state; + + // Entry point: sets the iteration limit to a new value. + internal static void SetIterationLimit(ulong workLimit) + { + Debug.Assert(t_state == null, "This method is not intended to be called recursively."); + State state = new State(); + state.RemainingAllowedWork = workLimit; + t_state = state; + } + + internal static bool WasWorkLimitExceeded() + { + Debug.Assert(t_state != null, "This method should only be called within a protected block."); + return t_state.WorkLimitWasExceeded; + } + + // Removes any iteration limit on the current thread. + internal static void ResetIterationLimit() + { + t_state = null; + } + + // Records that we're about to perform some amount of work. + // Overflows if the work count is exceeded. + internal static void RecordIterations(int workCount) + { + RecordIterations((long)workCount); + } + + // Records that we're about to perform some amount of work. + // Overflows if the work count is exceeded. + internal static void RecordIterations(long workCount) + { + State? state = t_state; + if (state == null) + { + return; + } + + bool success = false; + + if (workCount < 0) + { + throw new CryptographicException(); + } + + try + { + if (!state.WorkLimitWasExceeded) + { + state.RemainingAllowedWork = checked(state.RemainingAllowedWork - (ulong)workCount); + success = true; + } + } + finally + { + // If for any reason we failed, mark the thread as "no further work allowed" and + // normalize to CryptographicException. + if (!success) + { + state.RemainingAllowedWork = 0; + state.WorkLimitWasExceeded = true; + throw new CryptographicException(); + } + } + } + + private sealed class State + { + internal ulong RemainingAllowedWork; + internal bool WorkLimitWasExceeded; + } + } +} diff --git a/src/libraries/Common/src/System/Security/Cryptography/PasswordBasedEncryption.cs b/src/libraries/Common/src/System/Security/Cryptography/PasswordBasedEncryption.cs index dc1fd465acf..d988ad14288 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/PasswordBasedEncryption.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/PasswordBasedEncryption.cs @@ -377,6 +377,7 @@ private static CryptographicException AlgorithmKdfRequiresChars(string algId) Debug.Assert(pwdTmpBytes!.Length == 0); } + KdfWorkLimiter.RecordIterations(iterationCount); using (var pbkdf2 = new Rfc2898DeriveBytes(pwdTmpBytes, salt.ToArray(), iterationCount, prf)) { derivedKey = pbkdf2.GetBytes(keySizeBytes); diff --git a/src/libraries/Common/src/System/Security/Cryptography/Pkcs12Kdf.cs b/src/libraries/Common/src/System/Security/Cryptography/Pkcs12Kdf.cs index 132b7a7e354..feb6b9604b8 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Pkcs12Kdf.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Pkcs12Kdf.cs @@ -147,6 +147,7 @@ internal static class Pkcs12Kdf I = IRented.AsSpan(0, ILen); } + KdfWorkLimiter.RecordIterations(iterationCount); IncrementalHash hash = IncrementalHash.CreateHash(hashAlgorithm); try diff --git a/src/libraries/Common/tests/System/Net/Http/TestHelper.cs b/src/libraries/Common/tests/System/Net/Http/TestHelper.cs index 98c19464db9..b1ae822ea9e 100644 --- a/src/libraries/Common/tests/System/Net/Http/TestHelper.cs +++ b/src/libraries/Common/tests/System/Net/Http/TestHelper.cs @@ -157,7 +157,7 @@ public static X509Certificate2 CreateServerSelfSignedCertificate(string name = " X509Certificate2 cert = req.CreateSelfSigned(start, end); if (PlatformDetection.IsWindows) { - cert = new X509Certificate2(cert.Export(X509ContentType.Pfx)); + cert = new X509Certificate2(cert.Export(X509ContentType.Pfx), (string?)null); } return cert; diff --git a/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/RevocationResponder.cs b/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/RevocationResponder.cs index 4e9e5e20612..b08655e6f1d 100644 --- a/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/RevocationResponder.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/RevocationResponder.cs @@ -7,6 +7,7 @@ using System.Threading; using System.Threading.Tasks; using System.Web; +using Xunit; namespace System.Security.Cryptography.X509Certificates.Tests.Common { @@ -29,6 +30,7 @@ internal sealed class RevocationResponder : IDisposable public string UriPrefix { get; } public bool RespondEmpty { get; set; } + public AiaResponseKind AiaResponseKind { get; set; } public TimeSpan ResponseDelay { get; set; } public DelayedActionsFlag DelayedActions { get; set; } @@ -181,13 +183,13 @@ private void HandleRequest(HttpListenerContext context, ref bool responded) Thread.Sleep(ResponseDelay); } - byte[] certData = RespondEmpty ? Array.Empty() : authority.GetCertData(); + byte[] certData = RespondEmpty ? Array.Empty() : GetCertDataForAiaResponseKind(AiaResponseKind, authority); responded = true; context.Response.StatusCode = 200; - context.Response.ContentType = "application/pkix-cert"; + context.Response.ContentType = AiaResponseKindToContentType(AiaResponseKind); context.Response.Close(certData, willBlock: true); - Trace($"Responded with {certData.Length}-byte certificate from {authority.SubjectName}."); + Trace($"Responded with {certData.Length}-byte {AiaResponseKind} from {authority.SubjectName}."); return; } @@ -295,6 +297,41 @@ private static HttpListener OpenListener(out string uriPrefix) } } + private static string AiaResponseKindToContentType(AiaResponseKind kind) + { + if (kind == AiaResponseKind.Cert) + { + return "application/pkix-cert"; + } + else if (kind == AiaResponseKind.Pkcs12) + { + return "application/x-pkcs12"; + } + else + { + Assert.True(false, $"Unknown value AiaResponseKind.`{kind}`."); + return null; + } + } + + private static byte[] GetCertDataForAiaResponseKind(AiaResponseKind kind, CertificateAuthority authority) + { + if (kind == AiaResponseKind.Cert) + { + return authority.GetCertData(); + } + else if (kind == AiaResponseKind.Pkcs12) + { + using X509Certificate2 cert = new X509Certificate2(authority.GetCertData()); + return cert.Export(X509ContentType.Pkcs12); + } + else + { + Assert.True(false, $"Unknown value AiaResponseKind.`{kind}`."); + return null; + } + } + private static bool TryGetOcspRequestBytes(HttpListenerRequest request, string prefix, out byte[] requestBytes) { requestBytes = null; @@ -425,4 +462,10 @@ public enum DelayedActionsFlag : byte Aia = 0b100, All = 0b11111111 } + + public enum AiaResponseKind + { + Cert = 0, + Pkcs12 = 1, + } } diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs index bc8e3cf471b..b9917bee216 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs @@ -63,7 +63,7 @@ public static IEnumerable SslStream_StreamToStream_Authentication_Succ using (X509Certificate2 clientCert = Configuration.Certificates.GetClientCertificate()) { yield return new object[] { new X509Certificate2(serverCert), new X509Certificate2(clientCert) }; - yield return new object[] { new X509Certificate(serverCert.Export(X509ContentType.Pfx)), new X509Certificate(clientCert.Export(X509ContentType.Pfx)) }; + yield return new object[] { new X509Certificate(serverCert.Export(X509ContentType.Pfx), (string)null, X509KeyStorageFlags.DefaultKeySet), new X509Certificate(clientCert.Export(X509ContentType.Pfx), (string)null, X509KeyStorageFlags.DefaultKeySet) }; } } diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/TestHelper.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/TestHelper.cs index 68b66a1af51..e7f4761cd6d 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/TestHelper.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/TestHelper.cs @@ -169,7 +169,7 @@ internal static (X509Certificate2 certificate, X509Certificate2Collection) Gener if (PlatformDetection.IsWindows) { X509Certificate2 ephemeral = endEntity; - endEntity = new X509Certificate2(endEntity.Export(X509ContentType.Pfx)); + endEntity = new X509Certificate2(endEntity.Export(X509ContentType.Pfx), (string)null, X509KeyStorageFlags.DefaultKeySet); ephemeral.Dispose(); } diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj b/src/libraries/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj index 754b2e38861..827f8cb4692 100644 --- a/src/libraries/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj +++ b/src/libraries/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj @@ -1,4 +1,4 @@ - + true $(DefineConstants);INTERNAL_ASYMMETRIC_IMPLEMENTATIONS @@ -132,6 +132,8 @@ Link="Common\System\Security\Cryptography\KeyFormatHelper.cs" /> + + $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent);netcoreapp3.1-windows;netcoreapp3.1;netstandard2.1-windows;netstandard2.1;netstandard2.0-windows;netstandard2.0;net461-windows true - false - 2 + true + 3 Provides support for PKCS and CMS algorithms. Commonly Used Types: @@ -613,6 +613,8 @@ System.Security.Cryptography.Pkcs.EnvelopedCms Common\System\Security\Cryptography\Asn1\Pkcs7\EncryptedDataAsn.xml.cs Common\System\Security\Cryptography\Asn1\Pkcs7\EncryptedDataAsn.xml + - + diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Android/AndroidCertificatePal.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Android/AndroidCertificatePal.cs index d765cd0b56a..0110d34ac09 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Android/AndroidCertificatePal.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Android/AndroidCertificatePal.cs @@ -48,7 +48,7 @@ public static ICertificatePal FromOtherCert(X509Certificate cert) return new AndroidCertificatePal(handle); } - public static ICertificatePal FromBlob(ReadOnlySpan rawData, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags) + private static ICertificatePal FromBlob(ReadOnlySpan rawData, SafePasswordHandle password, bool readingFromFile, X509KeyStorageFlags keyStorageFlags) { Debug.Assert(password != null); @@ -68,6 +68,8 @@ public static ICertificatePal FromBlob(ReadOnlySpan rawData, SafePasswordH throw new PlatformNotSupportedException(SR.Cryptography_X509_PKCS12_PersistKeySetNotSupported); } + X509Certificate.EnforceIterationCountLimit(rawData, readingFromFile, password.PasswordProvided); + return ReadPkcs12(rawData, password, ephemeralSpecified); case X509ContentType.Cert: default: @@ -86,10 +88,15 @@ public static ICertificatePal FromBlob(ReadOnlySpan rawData, SafePasswordH throw new CryptographicException(); } + public static ICertificatePal FromBlob(ReadOnlySpan rawData, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags) + { + return FromBlob(rawData, password, readingFromFile: false, keyStorageFlags); + } + public static ICertificatePal FromFile(string fileName, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags) { byte[] fileBytes = System.IO.File.ReadAllBytes(fileName); - return FromBlob(fileBytes, password, keyStorageFlags); + return FromBlob(fileBytes, password, readingFromFile: true, keyStorageFlags); } // Handles both DER and PEM diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Android/StorePal.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Android/StorePal.cs index 6187979d905..d976ff167cc 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Android/StorePal.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Android/StorePal.cs @@ -18,7 +18,7 @@ public static IStorePal FromHandle(IntPtr storeHandle) throw new NotImplementedException($"{nameof(StorePal)}.{nameof(FromHandle)}"); } - public static ILoaderPal FromBlob(ReadOnlySpan rawData, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags) + private static ILoaderPal FromBlob(ReadOnlySpan rawData, SafePasswordHandle password, bool readingFromFile, X509KeyStorageFlags keyStorageFlags) { Debug.Assert(password != null); @@ -27,6 +27,7 @@ public static ILoaderPal FromBlob(ReadOnlySpan rawData, SafePasswordHandle if (contentType == X509ContentType.Pkcs12) { + X509Certificate.EnforceIterationCountLimit(rawData, readingFromFile, password.PasswordProvided); ICertificatePal[] certPals = ReadPkcs12Collection(rawData, password, ephemeralSpecified); return new AndroidCertLoader(certPals); } @@ -37,10 +38,15 @@ public static ILoaderPal FromBlob(ReadOnlySpan rawData, SafePasswordHandle } } + public static ILoaderPal FromBlob(ReadOnlySpan rawData, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags) + { + return FromBlob(rawData, password, readingFromFile: false, keyStorageFlags: keyStorageFlags); + } + public static ILoaderPal FromFile(string fileName, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags) { byte[] fileBytes = File.ReadAllBytes(fileName); - return FromBlob(fileBytes, password, keyStorageFlags); + return FromBlob(fileBytes, password, readingFromFile: true, keyStorageFlags: keyStorageFlags); } public static IExportPal FromCertificate(ICertificatePalCore cert) diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.OSX/AppleCertificatePal.ImportExport.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.OSX/AppleCertificatePal.ImportExport.cs index f6b19f9bb03..ad1aed066bf 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.OSX/AppleCertificatePal.ImportExport.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.OSX/AppleCertificatePal.ImportExport.cs @@ -23,6 +23,15 @@ internal sealed partial class AppleCertificatePal : ICertificatePal ReadOnlySpan rawData, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags) + { + return FromBlob(rawData, password, readingFromFile: false, keyStorageFlags); + } + + private static ICertificatePal FromBlob( + ReadOnlySpan rawData, + SafePasswordHandle password, + bool readingFromFile, + X509KeyStorageFlags keyStorageFlags) { Debug.Assert(password != null); @@ -47,6 +56,7 @@ internal sealed partial class AppleCertificatePal : ICertificatePal throw new PlatformNotSupportedException(SR.Cryptography_X509_NoEphemeralPfx); } + X509Certificate.EnforceIterationCountLimit(rawData, readingFromFile, password.PasswordProvided); bool exportable = (keyStorageFlags & X509KeyStorageFlags.Exportable) == X509KeyStorageFlags.Exportable; bool persist = diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.OSX/AppleCertificatePal.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.OSX/AppleCertificatePal.cs index 5334d9eb31a..045e0300347 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.OSX/AppleCertificatePal.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.OSX/AppleCertificatePal.cs @@ -76,7 +76,7 @@ public static ICertificatePal FromFile(string fileName, SafePasswordHandle passw Debug.Assert(password != null); byte[] fileBytes = System.IO.File.ReadAllBytes(fileName); - return FromBlob(fileBytes, password, keyStorageFlags); + return FromBlob(fileBytes, password, readingFromFile: true, keyStorageFlags); } internal AppleCertificatePal(SafeSecCertificateHandle certHandle) diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.OSX/StorePal.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.OSX/StorePal.cs index e7cbefeb5b4..ded349280b4 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.OSX/StorePal.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.OSX/StorePal.cs @@ -26,6 +26,11 @@ public static IStorePal FromHandle(IntPtr storeHandle) } public static ILoaderPal FromBlob(ReadOnlySpan rawData, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags) + { + return FromBlob(rawData, password, readingFromFile: false, keyStorageFlags); + } + + private static ILoaderPal FromBlob(ReadOnlySpan rawData, SafePasswordHandle password, bool readingFromFile, X509KeyStorageFlags keyStorageFlags) { Debug.Assert(password != null); @@ -38,6 +43,7 @@ public static ILoaderPal FromBlob(ReadOnlySpan rawData, SafePasswordHandle throw new PlatformNotSupportedException(SR.Cryptography_X509_NoEphemeralPfx); } + X509Certificate.EnforceIterationCountLimit(rawData, readingFromFile, password.PasswordProvided); bool exportable = (keyStorageFlags & X509KeyStorageFlags.Exportable) == X509KeyStorageFlags.Exportable; bool persist = @@ -87,7 +93,7 @@ public static ILoaderPal FromFile(string fileName, SafePasswordHandle password, Debug.Assert(password != null); byte[] fileBytes = File.ReadAllBytes(fileName); - return FromBlob(fileBytes, password, keyStorageFlags); + return FromBlob(fileBytes, password, readingFromFile: true, keyStorageFlags); } public static IExportPal FromCertificate(ICertificatePalCore cert) diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/CertificateAssetDownloader.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/CertificateAssetDownloader.cs index cd7ef4b8485..58cee08f57f 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/CertificateAssetDownloader.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/CertificateAssetDownloader.cs @@ -28,6 +28,16 @@ internal static class CertificateAssetDownloader try { + X509ContentType contentType = X509Certificate2.GetCertContentType(data); + switch (contentType) + { + case X509ContentType.Cert: + case X509ContentType.Pkcs7: + break; + default: + return null; + } + X509Certificate2 certificate = new X509Certificate2(data); certificate.ThrowIfInvalid(); return certificate; diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/OpenSslX509CertificateReader.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/OpenSslX509CertificateReader.cs index 27f1df388e7..bc8137d0bcc 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/OpenSslX509CertificateReader.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/OpenSslX509CertificateReader.cs @@ -55,7 +55,7 @@ public static ICertificatePal FromBlob(ReadOnlySpan rawData, SafePasswordH TryReadX509Pem(rawData, out cert) || PkcsFormatReader.TryReadPkcs7Der(rawData, out cert) || PkcsFormatReader.TryReadPkcs7Pem(rawData, out cert) || - PkcsFormatReader.TryReadPkcs12(rawData, password, ephemeralSpecified, out cert, out openSslException)) + PkcsFormatReader.TryReadPkcs12(rawData, password, ephemeralSpecified, readingFromFile: false, out cert, out openSslException)) { if (cert == null) { @@ -90,6 +90,7 @@ public static ICertificatePal FromFile(string fileName, SafePasswordHandle passw File.ReadAllBytes(fileName), password, ephemeralSpecified, + readingFromFile: true, out pal, out Exception? exception); diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/PkcsFormatReader.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/PkcsFormatReader.cs index f73b5937323..75c8029cb2e 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/PkcsFormatReader.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/PkcsFormatReader.cs @@ -6,6 +6,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; using Microsoft.Win32.SafeHandles; namespace Internal.Cryptography.Pal @@ -257,6 +258,7 @@ internal static bool TryReadPkcs7Pem(SafeBioHandle bio, [NotNullWhen(true)] out ReadOnlySpan rawData, SafePasswordHandle password, bool ephemeralSpecified, + bool readingFromFile, [NotNullWhen(true)] out ICertificatePal? certPal, out Exception? openSslException) { @@ -267,6 +269,7 @@ internal static bool TryReadPkcs7Pem(SafeBioHandle bio, [NotNullWhen(true)] out password, single: true, ephemeralSpecified, + readingFromFile, out certPal!, out ignored, out openSslException); @@ -276,6 +279,7 @@ internal static bool TryReadPkcs7Pem(SafeBioHandle bio, [NotNullWhen(true)] out ReadOnlySpan rawData, SafePasswordHandle password, bool ephemeralSpecified, + bool readingFromFile, [NotNullWhen(true)] out List? certPals, out Exception? openSslException) { @@ -286,6 +290,7 @@ internal static bool TryReadPkcs7Pem(SafeBioHandle bio, [NotNullWhen(true)] out password, single: false, ephemeralSpecified, + readingFromFile, out ignored, out certPals!, out openSslException); @@ -296,6 +301,7 @@ internal static bool TryReadPkcs7Pem(SafeBioHandle bio, [NotNullWhen(true)] out SafePasswordHandle password, bool single, bool ephemeralSpecified, + bool readingFromFile, out ICertificatePal? readPal, out List? readCerts, out Exception? openSslException) @@ -312,18 +318,21 @@ internal static bool TryReadPkcs7Pem(SafeBioHandle bio, [NotNullWhen(true)] out using (pfx) { - return TryReadPkcs12(pfx, password, single, ephemeralSpecified, out readPal, out readCerts); + return TryReadPkcs12(rawData, pfx, password, single, ephemeralSpecified, readingFromFile, out readPal, out readCerts); } } private static bool TryReadPkcs12( + ReadOnlySpan rawData, OpenSslPkcs12Reader pfx, SafePasswordHandle password, bool single, bool ephemeralSpecified, + bool readingFromFile, out ICertificatePal? readPal, out List? readCerts) { + X509Certificate.EnforceIterationCountLimit(rawData, readingFromFile, password.PasswordProvided); pfx.Decrypt(password, ephemeralSpecified); if (single) diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/StorePal.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/StorePal.cs index bef72007c38..576e9b1a8dc 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/StorePal.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/StorePal.cs @@ -40,7 +40,7 @@ public static ILoaderPal FromBlob(ReadOnlySpan rawData, SafePasswordHandle if (PkcsFormatReader.TryReadPkcs7Der(rawData, out certPals) || PkcsFormatReader.TryReadPkcs7Pem(rawData, out certPals) || - PkcsFormatReader.TryReadPkcs12(rawData, password, ephemeralSpecified, out certPals, out openSslException)) + PkcsFormatReader.TryReadPkcs12(rawData, password, ephemeralSpecified, readingFromFile: false, out certPals, out openSslException)) { Debug.Assert(certPals != null); @@ -111,7 +111,7 @@ public static ILoaderPal FromFile(string fileName, SafePasswordHandle password, // Capture the exception so in case of failure, the call to BioSeek does not override it. Exception? openSslException; byte[] data = File.ReadAllBytes(fileName); - if (PkcsFormatReader.TryReadPkcs12(data, password, ephemeralSpecified, out certPals, out openSslException)) + if (PkcsFormatReader.TryReadPkcs12(data, password, ephemeralSpecified, readingFromFile: true, out certPals, out openSslException)) { return ListToLoaderPal(certPals); } diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/CertificatePal.Import.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/CertificatePal.Import.cs index 72b4d63f2bc..9fe6922f5c5 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/CertificatePal.Import.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/CertificatePal.Import.cs @@ -83,7 +83,14 @@ out pCertContext else if (contentType == ContentType.CERT_QUERY_CONTENT_PFX) { if (loadFromFile) + { rawData = File.ReadAllBytes(fileName!); + } + else + { + X509Certificate.EnforceIterationCountLimit(rawData, readingFromFile: false, password.PasswordProvided); + } + pCertContext = FilterPFXStore(rawData, password, pfxCertStoreFlags); // If PersistKeySet is set we don't delete the key, so that it persists. diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/StorePal.Import.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/StorePal.Import.cs index d81149e93e3..c522278538e 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/StorePal.Import.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/StorePal.Import.cs @@ -6,6 +6,7 @@ using System; using System.IO; using System.Runtime.InteropServices; +using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Diagnostics; @@ -68,6 +69,11 @@ private static StorePal FromBlobOrFile(ReadOnlySpan rawData, string? fileN { rawData = File.ReadAllBytes(fileName!); } + else + { + X509Certificate.EnforceIterationCountLimit(rawData, readingFromFile: false, password.PasswordProvided); + } + fixed (byte* pRawData2 = rawData) { CRYPTOAPI_BLOB blob2 = new CRYPTOAPI_BLOB(rawData!.Length, pRawData2); diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.iOS/AppleCertificatePal.ImportExport.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.iOS/AppleCertificatePal.ImportExport.cs index dd8fb2ac2dd..8e8594ded22 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.iOS/AppleCertificatePal.ImportExport.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.iOS/AppleCertificatePal.ImportExport.cs @@ -99,6 +99,7 @@ internal static X509ContentType GetDerCertContentType(ReadOnlySpan rawData ReadOnlySpan rawData, X509ContentType contentType, SafePasswordHandle password, + bool readingFromFile, X509KeyStorageFlags keyStorageFlags) { Debug.Assert(password != null); @@ -124,6 +125,7 @@ internal static X509ContentType GetDerCertContentType(ReadOnlySpan rawData throw new PlatformNotSupportedException(SR.Cryptography_X509_PKCS12_PersistKeySetNotSupported); } + X509Certificate.EnforceIterationCountLimit(rawData, readingFromFile, password.PasswordProvided); return ImportPkcs12(rawData, password, ephemeralSpecified); } @@ -151,6 +153,15 @@ internal static X509ContentType GetDerCertContentType(ReadOnlySpan rawData ReadOnlySpan rawData, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags) + { + return FromBlob(rawData, password, readingFromFile: false, keyStorageFlags); + } + + public static ICertificatePal FromBlob( + ReadOnlySpan rawData, + SafePasswordHandle password, + bool readingFromFile, + X509KeyStorageFlags keyStorageFlags) { Debug.Assert(password != null); @@ -159,11 +170,11 @@ internal static X509ContentType GetDerCertContentType(ReadOnlySpan rawData rawData, (derData, contentType) => { - result = FromDerBlob(derData, contentType, password, keyStorageFlags); + result = FromDerBlob(derData, contentType, password, readingFromFile, keyStorageFlags); return false; }); - return result ?? FromDerBlob(rawData, GetDerCertContentType(rawData), password, keyStorageFlags); + return result ?? FromDerBlob(rawData, GetDerCertContentType(rawData), password, readingFromFile, keyStorageFlags); } public void DisposeTempKeychain() diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.iOS/AppleCertificatePal.Pkcs12.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.iOS/AppleCertificatePal.Pkcs12.cs index 8ff5988f557..d151d65a54b 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.iOS/AppleCertificatePal.Pkcs12.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.iOS/AppleCertificatePal.Pkcs12.cs @@ -18,7 +18,7 @@ namespace Internal.Cryptography.Pal { internal sealed partial class AppleCertificatePal : ICertificatePal { - private static SafePasswordHandle s_passwordExportHandle = new SafePasswordHandle("DotnetExportPassphrase"); + private static SafePasswordHandle s_passwordExportHandle = new SafePasswordHandle("DotnetExportPassphrase", passwordProvided: true); private static AppleCertificatePal ImportPkcs12( ReadOnlySpan rawData, diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.iOS/StorePal.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.iOS/StorePal.cs index 47d7485c0f9..e6b6dce07a7 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.iOS/StorePal.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.iOS/StorePal.cs @@ -19,7 +19,7 @@ public static IStorePal FromHandle(IntPtr storeHandle) throw new PlatformNotSupportedException($"{nameof(StorePal)}.{nameof(FromHandle)}"); } - public static ILoaderPal FromBlob(ReadOnlySpan rawData, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags) + private static ILoaderPal FromBlob(ReadOnlySpan rawData, SafePasswordHandle password, bool readingFromFile, X509KeyStorageFlags keyStorageFlags) { List? certificateList = null; @@ -28,7 +28,7 @@ public static ILoaderPal FromBlob(ReadOnlySpan rawData, SafePasswordHandle (derData, contentType) => { certificateList = certificateList ?? new List(); - certificateList.Add(AppleCertificatePal.FromDerBlob(derData, contentType, password, keyStorageFlags)); + certificateList.Add(AppleCertificatePal.FromDerBlob(derData, contentType, password, readingFromFile, keyStorageFlags)); return true; }); @@ -49,6 +49,7 @@ public static ILoaderPal FromBlob(ReadOnlySpan rawData, SafePasswordHandle if (contentType == X509ContentType.Pkcs12) { + X509Certificate.EnforceIterationCountLimit(rawData, readingFromFile, password.PasswordProvided); ApplePkcs12Reader reader = new ApplePkcs12Reader(rawData); try @@ -98,12 +99,17 @@ public static ILoaderPal FromBlob(ReadOnlySpan rawData, SafePasswordHandle return new CertCollectionLoader(certificateList); } + public static ILoaderPal FromBlob(ReadOnlySpan rawData, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags) + { + return FromBlob(rawData, password, readingFromFile: false, keyStorageFlags); + } + public static ILoaderPal FromFile(string fileName, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags) { Debug.Assert(password != null); byte[] fileBytes = File.ReadAllBytes(fileName); - return FromBlob(fileBytes, password, keyStorageFlags); + return FromBlob(fileBytes, password, readingFromFile: true, keyStorageFlags); } public static IExportPal FromCertificate(ICertificatePalCore cert) diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/Microsoft/Win32/SafeHandles/SafePasswordHandle.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/Microsoft/Win32/SafeHandles/SafePasswordHandle.cs index f528eae37b0..5bba8da0070 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/Microsoft/Win32/SafeHandles/SafePasswordHandle.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/Microsoft/Win32/SafeHandles/SafePasswordHandle.cs @@ -16,7 +16,13 @@ internal sealed partial class SafePasswordHandle : SafeHandleZeroOrMinusOneIsInv { internal int Length { get; private set; } - public SafePasswordHandle(string? password) + /// + /// This is used to track if a password was explicitly provided. + /// A null/empty password is a valid password. + /// + internal bool PasswordProvided { get; } + + public SafePasswordHandle(string? password, bool passwordProvided) : base(ownsHandle: true) { if (password != null) @@ -24,9 +30,11 @@ public SafePasswordHandle(string? password) handle = Marshal.StringToHGlobalUni(password); Length = password.Length; } + + PasswordProvided = passwordProvided; } - public SafePasswordHandle(ReadOnlySpan password) + public SafePasswordHandle(ReadOnlySpan password, bool passwordProvided) : base(ownsHandle: true) { // "".AsSpan() is not default, so this is compat for "null tries NULL first". @@ -49,9 +57,11 @@ public SafePasswordHandle(ReadOnlySpan password) Length = password.Length; } + + PasswordProvided = passwordProvided; } - public SafePasswordHandle(SecureString? password) + public SafePasswordHandle(SecureString? password, bool passwordProvided) : base(ownsHandle: true) { if (password != null) @@ -59,6 +69,8 @@ public SafePasswordHandle(SecureString? password) handle = Marshal.SecureStringToGlobalAllocUnicode(password); Length = password.Length; } + + PasswordProvided = passwordProvided; } protected override bool ReleaseHandle() @@ -96,7 +108,7 @@ internal ReadOnlySpan DangerousGetSpan() SafeHandleCache.GetInvalidHandle( () => { - var handle = new SafePasswordHandle((string?)null); + var handle = new SafePasswordHandle((string?)null, false); handle.handle = (IntPtr)(-1); return handle; }); diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/Resources/Strings.resx b/src/libraries/System.Security.Cryptography.X509Certificates/src/Resources/Strings.resx index b7e39a57646..d2e024f5fcf 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/Resources/Strings.resx +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/Resources/Strings.resx @@ -1,4 +1,4 @@ - + @@ -490,4 +490,7 @@ The certificate content type could not be determined. + + PKCS12 (PFX) without a supplied password has exceeded maximum allowed iterations. See https://go.microsoft.com/fwlink/?linkid=2233907 for more information. + diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/System.Security.Cryptography.X509Certificates.csproj b/src/libraries/System.Security.Cryptography.X509Certificates/src/System.Security.Cryptography.X509Certificates.csproj index 3b1071dd912..57abeec36ad 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/System.Security.Cryptography.X509Certificates.csproj +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/System.Security.Cryptography.X509Certificates.csproj @@ -30,14 +30,20 @@ Link="Common\System\Security\Cryptography\Oids.cs" /> + + + Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml @@ -60,6 +66,20 @@ Common\System\Security\Cryptography\Asn1\AttributeAsn.manual.cs Common\System\Security\Cryptography\Asn1\AttributeAsn.xml + + Common\System\Security\Cryptography\Asn1\Pkcs7\ContentInfoAsn.xml + + + Common\System\Security\Cryptography\Asn1\Pkcs7\ContentInfoAsn.xml.cs + Common\System\Security\Cryptography\Asn1\Pkcs7\ContentInfoAsn.xml + + + Common\System\Security\Cryptography\Asn1\DigestInfoAsn.xml + + + Common\System\Security\Cryptography\Asn1\DigestInfoAsn.xml.cs + Common\System\Security\Cryptography\Asn1\DigestInfoAsn.xml + Common\System\Security\Cryptography\Asn1\DirectoryStringAsn.xml @@ -74,6 +94,27 @@ Common\System\Security\Cryptography\Asn1\EdiPartyNameAsn.xml.cs Common\System\Security\Cryptography\Asn1\EdiPartyNameAsn.xml + + Common\System\Security\Cryptography\Asn1\Pkcs7\EncryptedContentInfoAsn.xml + + + Common\System\Security\Cryptography\Asn1\Pkcs7\EncryptedContentInfoAsn.xml.cs + Common\System\Security\Cryptography\Asn1\Pkcs7\EncryptedContentInfoAsn.xml + + + Common\System\Security\Cryptography\Asn1\Pkcs7\EncryptedDataAsn.xml + + + Common\System\Security\Cryptography\Asn1\Pkcs7\EncryptedDataAsn.xml.cs + Common\System\Security\Cryptography\Asn1\Pkcs7\EncryptedDataAsn.xml + + + Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml + + + Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml.cs + Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml + Common\System\Security\Cryptography\Asn1\GeneralNameAsn.xml @@ -81,6 +122,10 @@ Common\System\Security\Cryptography\Asn1\GeneralNameAsn.xml.cs Common\System\Security\Cryptography\Asn1\GeneralNameAsn.xml + + Common\System\Security\Cryptography\Asn1\Pkcs12\MacData.xml.cs + Common\System\Security\Cryptography\Asn1\Pkcs12\MacData.xml + Common\System\Security\Cryptography\Asn1\OtherNameAsn.xml @@ -88,6 +133,48 @@ Common\System\Security\Cryptography\Asn1\OtherNameAsn.xml.cs Common\System\Security\Cryptography\Asn1\OtherNameAsn.xml + + Common\System\Security\Cryptography\Asn1\PBEParameter.xml + + + Common\System\Security\Cryptography\Asn1\PBEParameter.xml.cs + Common\System\Security\Cryptography\Asn1\PBEParameter.xml + + + Common\System\Security\Cryptography\Asn1\PBES2Params.xml + + + Common\System\Security\Cryptography\Asn1\PBES2Params.xml.cs + Common\System\Security\Cryptography\Asn1\PBES2Params.xml + + + Common\System\Security\Cryptography\Asn1\Pbkdf2Params.xml + + + Common\System\Security\Cryptography\Asn1\Pbkdf2Params.xml.cs + Common\System\Security\Cryptography\Asn1\Pbkdf2Params.xml + + + Common\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml + + + Common\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml.cs + Common\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml + + + Common\System\Security\Cryptography\Asn1\Pkcs12\MacData.xml + + + Common\System\Security\Cryptography\Asn1\Pkcs12\PfxAsn.xml + + + Common\System\Security\Cryptography\Asn1\Pkcs12\PfxAsn.manual.cs + Common\System\Security\Cryptography\Asn1\Pkcs12\PfxAsn.xml + + + Common\System\Security\Cryptography\Asn1\Pkcs12\PfxAsn.xml.cs + Common\System\Security\Cryptography\Asn1\Pkcs12\PfxAsn.xml + Common\System\Security\Cryptography\Asn1\PssParamsAsn.xml @@ -95,6 +182,24 @@ Common\System\Security\Cryptography\Asn1\PssParamsAsn.xml.cs Common\System\Security\Cryptography\Asn1\PssParamsAsn.xml + + Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml + + + Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml.cs + Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml + + + Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.manual.cs + Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml + + + Common\System\Security\Cryptography\Asn1\Pkcs12\SafeBagAsn.xml + + + Common\System\Security\Cryptography\Asn1\Pkcs12\SafeBagAsn.xml.cs + Common\System\Security\Cryptography\Asn1\Pkcs12\SafeBagAsn.xml + Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml @@ -135,6 +240,9 @@ + + @@ -198,6 +306,7 @@ System\Security\Cryptography\X509Certificates\Asn1\CertificationRequestInfoAsn.xml + System\Security\Cryptography\X509Certificates\Asn1\TbsCertificateAsn.xml @@ -411,7 +520,7 @@ + Link="Common\Internal\Cryptography\AsymmetricAlgorithmHelpers.Hash.cs" /> - - - - Common\System\Security\Cryptography\Asn1\DigestInfoAsn.xml - - - Common\System\Security\Cryptography\Asn1\DigestInfoAsn.xml.cs - Common\System\Security\Cryptography\Asn1\DigestInfoAsn.xml - - - Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml - - - Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml.cs - Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml - Common\System\Security\Cryptography\Asn1\Pkcs12\CertBagAsn.xml @@ -671,80 +762,6 @@ Common\System\Security\Cryptography\Asn1\Pkcs12\CertBagAsn.xml.cs Common\System\Security\Cryptography\Asn1\Pkcs12\CertBagAsn.xml - - Common\System\Security\Cryptography\Asn1\Pkcs12\MacData.xml - - - Common\System\Security\Cryptography\Asn1\Pkcs12\MacData.xml.cs - Common\System\Security\Cryptography\Asn1\Pkcs12\MacData.xml - - - Common\System\Security\Cryptography\Asn1\Pkcs12\PfxAsn.xml - - - Common\System\Security\Cryptography\Asn1\Pkcs12\PfxAsn.manual.cs - Common\System\Security\Cryptography\Asn1\Pkcs12\PfxAsn.xml - - - Common\System\Security\Cryptography\Asn1\Pkcs12\PfxAsn.xml.cs - Common\System\Security\Cryptography\Asn1\Pkcs12\PfxAsn.xml - - - Common\System\Security\Cryptography\Asn1\Pkcs12\SafeBagAsn.xml - - - Common\System\Security\Cryptography\Asn1\Pkcs12\SafeBagAsn.xml.cs - Common\System\Security\Cryptography\Asn1\Pkcs12\SafeBagAsn.xml - - - Common\System\Security\Cryptography\Asn1\Pkcs7\ContentInfoAsn.xml - - - Common\System\Security\Cryptography\Asn1\Pkcs7\ContentInfoAsn.xml.cs - Common\System\Security\Cryptography\Asn1\Pkcs7\ContentInfoAsn.xml - - - Common\System\Security\Cryptography\Asn1\PBEParameter.xml - - - Common\System\Security\Cryptography\Asn1\PBEParameter.xml.cs - Common\System\Security\Cryptography\Asn1\PBEParameter.xml - - - Common\System\Security\Cryptography\Asn1\PBES2Params.xml - - - Common\System\Security\Cryptography\Asn1\PBES2Params.xml.cs - Common\System\Security\Cryptography\Asn1\PBES2Params.xml - - - Common\System\Security\Cryptography\Asn1\Pbkdf2Params.xml - - - Common\System\Security\Cryptography\Asn1\Pbkdf2Params.xml.cs - Common\System\Security\Cryptography\Asn1\Pbkdf2Params.xml - - - Common\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml - - - Common\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml.cs - Common\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml - - - Common\System\Security\Cryptography\Asn1\Pkcs7\EncryptedContentInfoAsn.xml - - - Common\System\Security\Cryptography\Asn1\Pkcs7\EncryptedContentInfoAsn.xml.cs - Common\System\Security\Cryptography\Asn1\Pkcs7\EncryptedContentInfoAsn.xml - - - Common\System\Security\Cryptography\Asn1\Pkcs7\EncryptedDataAsn.xml - - - Common\System\Security\Cryptography\Asn1\Pkcs7\EncryptedDataAsn.xml.cs - Common\System\Security\Cryptography\Asn1\Pkcs7\EncryptedDataAsn.xml - Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml @@ -752,17 +769,6 @@ Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml.cs Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml - - Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml - - - Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml.cs - Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml - - - Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.manual.cs - Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml - diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/PfxAsn.manual.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/PfxAsn.manual.cs new file mode 100644 index 00000000000..aba715f7e3e --- /dev/null +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/PfxAsn.manual.cs @@ -0,0 +1,258 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Internal.Cryptography; +using System.Diagnostics; +using System.Formats.Asn1; +using System.Security.Cryptography.Asn1.Pkcs7; +using System.Security.Cryptography.Asn1.Pkcs12; + +namespace System.Security.Cryptography.Asn1.Pkcs12 +{ + internal partial struct PfxAsn + { + private const int MaxIterationWork = 300_000; + private static ReadOnlySpan EmptyPassword => ""; // don't use ReadOnlySpan.Empty because it will get confused with default. + private static ReadOnlySpan NullPassword => default; + + internal ulong CountTotalIterations() + { + checked + { + ulong count = 0; + + // RFC 7292 section 4.1: + // the contentType field of authSafe shall be of type data + // or signedData. The content field of the authSafe shall, either + // directly (data case) or indirectly (signedData case), contain a BER- + // encoded value of type AuthenticatedSafe. + // We don't support authSafe that is signedData, so enforce that it's just data. + if (AuthSafe.ContentType != Oids.Pkcs7Data) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); + } + + ReadOnlyMemory authSafeContents = Helpers.DecodeOctetStringAsMemory(AuthSafe.Content); + AsnValueReader outerAuthSafe = new AsnValueReader(authSafeContents.Span, AsnEncodingRules.BER); // RFC 7292 PDU says BER + AsnValueReader authSafeReader = outerAuthSafe.ReadSequence(); + outerAuthSafe.ThrowIfNotEmpty(); + + bool hasSeenEncryptedInfo = false; + + while (authSafeReader.HasData) + { + ContentInfoAsn.Decode(ref authSafeReader, authSafeContents, out ContentInfoAsn contentInfo); + + ReadOnlyMemory contentData; + ArraySegment? rentedData = null; + + try + { + if (contentInfo.ContentType != Oids.Pkcs7Data) + { + if (contentInfo.ContentType == Oids.Pkcs7Encrypted) + { + if (hasSeenEncryptedInfo) + { + // We will process at most one encryptedData ContentInfo. This is the most typical scenario where + // certificates are stored in an encryptedData ContentInfo, and keys are shrouded in a data ContentInfo. + throw new CryptographicException(SR.Cryptography_X509_PfxWithoutPassword); + } + + ArraySegment content = DecryptContentInfo(contentInfo, out uint iterations); + contentData = content; + rentedData = content; + hasSeenEncryptedInfo = true; + count += iterations; + } + else + { + // Not a common scenario. It's not data or encryptedData, so they need to go through the + // regular PKCS12 loader. + throw new CryptographicException(SR.Cryptography_X509_PfxWithoutPassword); + } + } + else + { + contentData = Helpers.DecodeOctetStringAsMemory(contentInfo.Content); + } + + AsnValueReader outerSafeBag = new AsnValueReader(contentData.Span, AsnEncodingRules.BER); + AsnValueReader safeBagReader = outerSafeBag.ReadSequence(); + outerSafeBag.ThrowIfNotEmpty(); + + while (safeBagReader.HasData) + { + SafeBagAsn.Decode(ref safeBagReader, contentData, out SafeBagAsn bag); + + // We only need to count iterations on PKCS8ShroudedKeyBag. + // * KeyBag is PKCS#8 PrivateKeyInfo and doesn't do iterations. + // * CertBag, either for x509Certificate or sdsiCertificate don't do iterations. + // * CRLBag doesn't do iterations. + // * SecretBag doesn't do iteations. + // * Nested SafeContents _can_ do iterations, but Windows ignores it. So we will ignore it too. + if (bag.BagId == Oids.Pkcs12ShroudedKeyBag) + { + AsnValueReader pkcs8ShroudedKeyReader = new AsnValueReader(bag.BagValue.Span, AsnEncodingRules.BER); + EncryptedPrivateKeyInfoAsn.Decode( + ref pkcs8ShroudedKeyReader, + bag.BagValue, + out EncryptedPrivateKeyInfoAsn epki); + + count += IterationsFromParameters(epki.EncryptionAlgorithm); + } + } + } + finally + { + if (rentedData.HasValue) + { + CryptoPool.Return(rentedData.Value); + } + } + } + + if (MacData.HasValue) + { + if (MacData.Value.IterationCount < 0) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); + } + + count += (uint)MacData.Value.IterationCount; + } + + return count; + } + } + + private static ArraySegment DecryptContentInfo(ContentInfoAsn contentInfo, out uint iterations) + { + EncryptedDataAsn encryptedData = EncryptedDataAsn.Decode(contentInfo.Content, AsnEncodingRules.BER); + + if (encryptedData.Version != 0 && encryptedData.Version != 2) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); + } + + // The encrypted contentInfo can only wrap a PKCS7 data. + if (encryptedData.EncryptedContentInfo.ContentType != Oids.Pkcs7Data) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); + } + + if (!encryptedData.EncryptedContentInfo.EncryptedContent.HasValue) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); + } + + iterations = IterationsFromParameters(encryptedData.EncryptedContentInfo.ContentEncryptionAlgorithm); + + // This encryptData is encrypted with more rounds than we are willing to process. Bail out of the whole thing. + if (iterations > MaxIterationWork) + { + throw new CryptographicException(SR.Cryptography_X509_PfxWithoutPassword); + } + + int encryptedValueLength = encryptedData.EncryptedContentInfo.EncryptedContent.Value.Length; + byte[] destination = CryptoPool.Rent(encryptedValueLength); + int written = 0; + + try + { + try + { + written = PasswordBasedEncryption.Decrypt( + in encryptedData.EncryptedContentInfo.ContentEncryptionAlgorithm, + EmptyPassword, + default, + encryptedData.EncryptedContentInfo.EncryptedContent.Value.Span, + destination); + } + catch + { + // If empty password didn't work, try null password. + written = PasswordBasedEncryption.Decrypt( + in encryptedData.EncryptedContentInfo.ContentEncryptionAlgorithm, + NullPassword, + default, + encryptedData.EncryptedContentInfo.EncryptedContent.Value.Span, + destination); + } + } + finally + { + if (written == 0) + { + // This means the decryption operation failed and destination could contain + // partial data. Clear it to be hygienic. + CryptographicOperations.ZeroMemory(destination); + } + } + + return new ArraySegment(destination, 0, written); + } + + private static uint IterationsFromParameters(in AlgorithmIdentifierAsn algorithmIdentifier) + { + switch (algorithmIdentifier.Algorithm) + { + case Oids.PasswordBasedEncryptionScheme2: + if (!algorithmIdentifier.Parameters.HasValue) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); + } + + PBES2Params pbes2Params = PBES2Params.Decode(algorithmIdentifier.Parameters.Value, AsnEncodingRules.BER); + + // PBES2 only defines PKBDF2 for now. See RFC 8018 A.4 + if (pbes2Params.KeyDerivationFunc.Algorithm != Oids.Pbkdf2) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); + } + + if (!pbes2Params.KeyDerivationFunc.Parameters.HasValue) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); + } + + Pbkdf2Params pbkdf2Params = Pbkdf2Params.Decode(pbes2Params.KeyDerivationFunc.Parameters.Value, AsnEncodingRules.BER); + + if (pbkdf2Params.IterationCount < 0) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); + } + + return (uint)pbkdf2Params.IterationCount; + + // PBES1 + case Oids.PbeWithMD5AndDESCBC: + case Oids.PbeWithMD5AndRC2CBC: + case Oids.PbeWithSha1AndDESCBC: + case Oids.PbeWithSha1AndRC2CBC: + case Oids.Pkcs12PbeWithShaAnd3Key3Des: + case Oids.Pkcs12PbeWithShaAnd2Key3Des: + case Oids.Pkcs12PbeWithShaAnd128BitRC2: + case Oids.Pkcs12PbeWithShaAnd40BitRC2: + if (!algorithmIdentifier.Parameters.HasValue) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); + } + + PBEParameter pbeParameters = PBEParameter.Decode( + algorithmIdentifier.Parameters.Value, + AsnEncodingRules.BER); + + if (pbeParameters.IterationCount < 0) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); + } + + return (uint)pbeParameters.IterationCount; + + default: + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); + } + } + } +} diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/LocalAppContextSwitches.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/LocalAppContextSwitches.cs new file mode 100644 index 00000000000..0b7eb187e76 --- /dev/null +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/LocalAppContextSwitches.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System +{ + internal static partial class LocalAppContextSwitches + { + internal const long DefaultPkcs12UnspecifiedPasswordIterationLimit = 600_000; + + internal static long Pkcs12UnspecifiedPasswordIterationLimit { get; } = InitializePkcs12UnspecifiedPasswordIterationLimit(); + + private static long InitializePkcs12UnspecifiedPasswordIterationLimit() + { + object? data = AppContext.GetData("System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit"); + + if (data is null) + { + return DefaultPkcs12UnspecifiedPasswordIterationLimit; + } + + try + { + return Convert.ToInt64(data); + } + catch + { + return DefaultPkcs12UnspecifiedPasswordIterationLimit; + } + } + } +} diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/X509Certificate.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/X509Certificate.cs index 1913afa2af2..c1b773db784 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/X509Certificate.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/X509Certificate.cs @@ -5,10 +5,13 @@ using Internal.Cryptography.Pal; using Microsoft.Win32.SafeHandles; using System; +using System.Buffers; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Formats.Asn1; using System.Globalization; using System.Runtime.Serialization; +using System.Security.Cryptography.Asn1.Pkcs12; using System.Text; namespace System.Security.Cryptography.X509Certificates @@ -61,7 +64,7 @@ private protected X509Certificate(ReadOnlySpan data) if (!data.IsEmpty) { // For compat reasons, this constructor treats passing a null or empty data set as the same as calling the nullary constructor. - using (var safePasswordHandle = new SafePasswordHandle((string?)null)) + using (var safePasswordHandle = new SafePasswordHandle((string?)null, passwordProvided: false)) { Pal = CertificatePal.FromBlob(data, safePasswordHandle, X509KeyStorageFlags.DefaultKeySet); } @@ -86,7 +89,7 @@ public X509Certificate(byte[] rawData, string? password, X509KeyStorageFlags key ValidateKeyStorageFlags(keyStorageFlags); - using (var safePasswordHandle = new SafePasswordHandle(password)) + using (var safePasswordHandle = new SafePasswordHandle(password, passwordProvided: true)) { Pal = CertificatePal.FromBlob(rawData, safePasswordHandle, keyStorageFlags); } @@ -100,7 +103,7 @@ public X509Certificate(byte[] rawData, SecureString? password, X509KeyStorageFla ValidateKeyStorageFlags(keyStorageFlags); - using (var safePasswordHandle = new SafePasswordHandle(password)) + using (var safePasswordHandle = new SafePasswordHandle(password, passwordProvided: true)) { Pal = CertificatePal.FromBlob(rawData, safePasswordHandle, keyStorageFlags); } @@ -113,7 +116,7 @@ private protected X509Certificate(ReadOnlySpan rawData, ReadOnlySpan ValidateKeyStorageFlags(keyStorageFlags); - using (var safePasswordHandle = new SafePasswordHandle(password)) + using (var safePasswordHandle = new SafePasswordHandle(password, passwordProvided: true)) { Pal = CertificatePal.FromBlob(rawData, safePasswordHandle, keyStorageFlags); } @@ -153,7 +156,7 @@ public X509Certificate(string fileName, string? password, X509KeyStorageFlags ke ValidateKeyStorageFlags(keyStorageFlags); - using (var safePasswordHandle = new SafePasswordHandle(password)) + using (var safePasswordHandle = new SafePasswordHandle(password, passwordProvided: true)) { Pal = CertificatePal.FromFile(fileName, safePasswordHandle, keyStorageFlags); } @@ -166,7 +169,7 @@ private protected X509Certificate(string fileName, ReadOnlySpan password, ValidateKeyStorageFlags(keyStorageFlags); - using (var safePasswordHandle = new SafePasswordHandle(password)) + using (var safePasswordHandle = new SafePasswordHandle(password, passwordProvided: true)) { Pal = CertificatePal.FromFile(fileName, safePasswordHandle, keyStorageFlags); } @@ -182,7 +185,7 @@ public X509Certificate(string fileName, SecureString? password, X509KeyStorageFl ValidateKeyStorageFlags(keyStorageFlags); - using (var safePasswordHandle = new SafePasswordHandle(password)) + using (var safePasswordHandle = new SafePasswordHandle(password, passwordProvided: true)) { Pal = CertificatePal.FromFile(fileName, safePasswordHandle, keyStorageFlags); } @@ -321,7 +324,7 @@ public virtual byte[] Export(X509ContentType contentType, string? password) if (Pal == null) throw new CryptographicException(ErrorCode.E_POINTER); // Not the greatest error, but needed for backward compat. - using (var safePasswordHandle = new SafePasswordHandle(password)) + using (var safePasswordHandle = new SafePasswordHandle(password, passwordProvided: true)) { return Pal.Export(contentType, safePasswordHandle); } @@ -335,7 +338,7 @@ public virtual byte[] Export(X509ContentType contentType, SecureString? password if (Pal == null) throw new CryptographicException(ErrorCode.E_POINTER); // Not the greatest error, but needed for backward compat. - using (var safePasswordHandle = new SafePasswordHandle(password)) + using (var safePasswordHandle = new SafePasswordHandle(password, passwordProvided: true)) { return Pal.Export(contentType, safePasswordHandle); } @@ -694,6 +697,88 @@ private void VerifyContentType(X509ContentType contentType) throw new CryptographicException(SR.Cryptography_X509_InvalidContentType); } + internal static void EnforceIterationCountLimit(ReadOnlySpan pkcs12, bool readingFromFile, bool passwordProvided) + { + if (readingFromFile || passwordProvided) + { + return; + } + + long pkcs12UnspecifiedPasswordIterationLimit = LocalAppContextSwitches.Pkcs12UnspecifiedPasswordIterationLimit; + + // -1 = no limit + if (LocalAppContextSwitches.Pkcs12UnspecifiedPasswordIterationLimit == -1) + { + return; + } + + // any other negative number means use default limits + if (pkcs12UnspecifiedPasswordIterationLimit < 0) + { + pkcs12UnspecifiedPasswordIterationLimit = LocalAppContextSwitches.DefaultPkcs12UnspecifiedPasswordIterationLimit; + } + + try + { + try + { + checked + { + KdfWorkLimiter.SetIterationLimit((ulong)pkcs12UnspecifiedPasswordIterationLimit); + ulong observedIterationCount = GetIterationCount(pkcs12); + + // Check both conditions: we want a KDF-exceeded failure anywhere in the system to produce a failure here. + // There are some places within the GetIterationCount method where we optimistically try processing the + // PFX in one manner, and if we see failures we'll swallow any exceptions and try a different manner + // instead. The problem with this is that when we swallow failures, we don't have the ability to add the + // so-far-observed iteration count back to the running total returned by GetIterationCount. This + // potentially allows a clever adversary a window through which to squeeze in work beyond our configured + // limits. To mitigate this risk, we'll fail now if we observed *any* KDF-exceeded failure while processing + // this PFX. + if (observedIterationCount > (ulong)pkcs12UnspecifiedPasswordIterationLimit || KdfWorkLimiter.WasWorkLimitExceeded()) + { + throw new CryptographicException(); // iteration count exceeded + } + } + } + finally + { + KdfWorkLimiter.ResetIterationLimit(); + } + } + catch (Exception ex) + { + // It's important for this catch-all block to be *outside* the inner try/finally + // so that we can prevent exception filters from running before we've had a chance + // to clean up the threadstatic. + throw new CryptographicException(SR.Cryptography_X509_PfxWithoutPassword, ex); + } + } + + internal static ulong GetIterationCount(ReadOnlySpan pkcs12) + { + ulong iterations; + + unsafe + { + fixed (byte* pin = pkcs12) + { + using (var manager = new PointerMemoryManager(pin, pkcs12.Length)) + { + AsnValueReader reader = new AsnValueReader(pkcs12, AsnEncodingRules.BER); + PfxAsn.Decode(ref reader, manager.Memory, out PfxAsn pfx); + + // Don't throw when trailing data is present. + // Windows doesn't have such enforcement as well. + + iterations = pfx.CountTotalIterations(); + } + } + } + + return iterations; + } + internal const X509KeyStorageFlags KeyStorageFlagsAll = X509KeyStorageFlags.UserKeySet | X509KeyStorageFlags.MachineKeySet | diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/X509Certificate2Collection.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/X509Certificate2Collection.cs index c0b695d17da..b7f06862bb1 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/X509Certificate2Collection.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/X509Certificate2Collection.cs @@ -109,12 +109,16 @@ public bool Contains(X509Certificate2 certificate) public byte[]? Export(X509ContentType contentType) { - return Export(contentType, password: null); + using (var safePasswordHandle = new SafePasswordHandle((string?)null, passwordProvided: false)) + using (IExportPal storePal = StorePal.LinkFromCertificateCollection(this)) + { + return storePal.Export(contentType, safePasswordHandle); + } } public byte[]? Export(X509ContentType contentType, string? password) { - using (var safePasswordHandle = new SafePasswordHandle(password)) + using (var safePasswordHandle = new SafePasswordHandle(password, passwordProvided: true)) using (IExportPal storePal = StorePal.LinkFromCertificateCollection(this)) { return storePal.Export(contentType, safePasswordHandle); @@ -152,7 +156,11 @@ public void Import(byte[] rawData) /// public void Import(ReadOnlySpan rawData) { - Import(rawData, password: null, keyStorageFlags: X509KeyStorageFlags.DefaultKeySet); + using (var safePasswordHandle = new SafePasswordHandle((string?)null, passwordProvided: false)) + using (ILoaderPal storePal = StorePal.FromBlob(rawData, safePasswordHandle, X509KeyStorageFlags.DefaultKeySet)) + { + storePal.MoveTo(this); + } } public void Import(byte[] rawData, string? password, X509KeyStorageFlags keyStorageFlags = 0) @@ -199,7 +207,7 @@ public void Import(ReadOnlySpan rawData, ReadOnlySpan password, X509 X509Certificate.ValidateKeyStorageFlags(keyStorageFlags); - using (var safePasswordHandle = new SafePasswordHandle(password)) + using (var safePasswordHandle = new SafePasswordHandle(password, passwordProvided: true)) using (ILoaderPal storePal = StorePal.FromBlob(rawData, safePasswordHandle, keyStorageFlags)) { storePal.MoveTo(this); @@ -208,7 +216,14 @@ public void Import(ReadOnlySpan rawData, ReadOnlySpan password, X509 public void Import(string fileName) { - Import(fileName, password: null, keyStorageFlags: X509KeyStorageFlags.DefaultKeySet); + if (fileName == null) + throw new ArgumentNullException(nameof(fileName)); + + using (var safePasswordHandle = new SafePasswordHandle((string?)null, passwordProvided: false)) + using (ILoaderPal storePal = StorePal.FromFile(fileName, safePasswordHandle, X509KeyStorageFlags.DefaultKeySet)) + { + storePal.MoveTo(this); + } } public void Import(string fileName, string? password, X509KeyStorageFlags keyStorageFlags = 0) @@ -218,7 +233,7 @@ public void Import(string fileName, string? password, X509KeyStorageFlags keySto X509Certificate.ValidateKeyStorageFlags(keyStorageFlags); - using (var safePasswordHandle = new SafePasswordHandle(password)) + using (var safePasswordHandle = new SafePasswordHandle(password, passwordProvided: true)) using (ILoaderPal storePal = StorePal.FromFile(fileName, safePasswordHandle, keyStorageFlags)) { storePal.MoveTo(this); @@ -244,7 +259,7 @@ public void Import(string fileName, ReadOnlySpan password, X509KeyStorageF X509Certificate.ValidateKeyStorageFlags(keyStorageFlags); - using (var safePasswordHandle = new SafePasswordHandle(password)) + using (var safePasswordHandle = new SafePasswordHandle(password, passwordProvided: true)) using (ILoaderPal storePal = StorePal.FromFile(fileName, safePasswordHandle, keyStorageFlags)) { storePal.MoveTo(this); diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/tests/CertTests.cs b/src/libraries/System.Security.Cryptography.X509Certificates/tests/CertTests.cs index 41b8084ae55..abb78cc2392 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/tests/CertTests.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/tests/CertTests.cs @@ -411,7 +411,7 @@ public static void ExportPublicKeyAsPkcs12() // Read it back as a collection, there should be only one cert, and it should // be equal to the one we started with. - using (ImportedCollection ic = Cert.Import(pkcs12Bytes)) + using (ImportedCollection ic = Cert.Import(pkcs12Bytes, (string?)null, X509KeyStorageFlags.DefaultKeySet)) { X509Certificate2Collection fromPfx = ic.Collection; diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/tests/CollectionImportTests.cs b/src/libraries/System.Security.Cryptography.X509Certificates/tests/CollectionImportTests.cs index d46d734b5ce..a292d8e4828 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/tests/CollectionImportTests.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/tests/CollectionImportTests.cs @@ -22,7 +22,7 @@ public static void ImportNull() [Fact] public static void ImportEmpty_Pkcs12() { - using (ImportedCollection ic = Cert.Import(TestData.EmptyPfx)) + using (ImportedCollection ic = Cert.Import(TestData.EmptyPfx, (string?)null, X509KeyStorageFlags.DefaultKeySet)) { X509Certificate2Collection collection = ic.Collection; Assert.Equal(0, collection.Count); diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/tests/CollectionTests.cs b/src/libraries/System.Security.Cryptography.X509Certificates/tests/CollectionTests.cs index 0392b093e87..e20cd08198d 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/tests/CollectionTests.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/tests/CollectionTests.cs @@ -635,7 +635,7 @@ public static void ImportFromFileTests(X509KeyStorageFlags storageFlags) [Fact] public static void ImportMultiplePrivateKeysPfx() { - using (ImportedCollection ic = Cert.Import(TestData.MultiPrivateKeyPfx)) + using (ImportedCollection ic = Cert.Import(TestData.MultiPrivateKeyPfx, (string?)null, X509KeyStorageFlags.DefaultKeySet)) { X509Certificate2Collection collection = ic.Collection; @@ -751,7 +751,7 @@ public static void ExportUnrelatedPfx() byte[] exported = collection.Export(X509ContentType.Pkcs12); - using (ImportedCollection ic = Cert.Import(exported)) + using (ImportedCollection ic = Cert.Import(exported, (string?)null, X509KeyStorageFlags.DefaultKeySet)) { X509Certificate2Collection importedCollection = ic.Collection; @@ -813,7 +813,7 @@ public static void ExportMultiplePrivateKeys() byte[] exported = collection.Export(X509ContentType.Pkcs12); - using (ImportedCollection ic = Cert.Import(exported)) + using (ImportedCollection ic = Cert.Import(exported, (string?)null, X509KeyStorageFlags.DefaultKeySet)) { X509Certificate2Collection importedCollection = ic.Collection; @@ -852,7 +852,7 @@ public static void CanAddMultipleCertsWithSinglePrivateKey() byte[] buffer = col.Export(X509ContentType.Pfx); - using (ImportedCollection newCollection = Cert.Import(buffer)) + using (ImportedCollection newCollection = Cert.Import(buffer, (string?)null, X509KeyStorageFlags.DefaultKeySet)) { Assert.Equal(2, newCollection.Collection.Count); } diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/tests/ExportTests.cs b/src/libraries/System.Security.Cryptography.X509Certificates/tests/ExportTests.cs index 951a1329b77..0799f496327 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/tests/ExportTests.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/tests/ExportTests.cs @@ -65,7 +65,7 @@ public static void ExportAsPfx() byte[] pfx = c1.Export(X509ContentType.Pkcs12); Assert.Equal(X509ContentType.Pkcs12, X509Certificate2.GetCertContentType(pfx)); - using (X509Certificate2 c2 = new X509Certificate2(pfx)) + using (X509Certificate2 c2 = new X509Certificate2(pfx, (string?)null)) { byte[] rawData = c2.Export(X509ContentType.Cert); Assert.Equal(TestData.MsCertificate, rawData); @@ -134,7 +134,7 @@ public static void ExportAsPfxWithPrivateKey() byte[] pfxBytes = cert.Export(X509ContentType.Pkcs12); - using (X509Certificate2 fromPfx = new X509Certificate2(pfxBytes)) + using (X509Certificate2 fromPfx = new X509Certificate2(pfxBytes, (string?)null)) { Assert.Equal(cert, fromPfx); Assert.True(fromPfx.HasPrivateKey, "fromPfx.HasPrivateKey"); diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxIterationCountTests.CustomAppDomainDataLimit.cs b/src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxIterationCountTests.CustomAppDomainDataLimit.cs new file mode 100644 index 00000000000..6ed0734deaa --- /dev/null +++ b/src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxIterationCountTests.CustomAppDomainDataLimit.cs @@ -0,0 +1,139 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.DotNet.RemoteExecutor; +using Microsoft.DotNet.XUnitExtensions; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography.X509Certificates; +using Xunit; + +namespace System.Security.Cryptography.X509Certificates.Tests +{ + // AppContext and AppDomain are the same in this context. + public class PfxIterationCountTests_CustomAppDomainDataLimit + { + // We need to use virtual in a non-abstract class because RemoteExecutor can't work on abstract classes. + internal virtual X509Certificate Import(byte[] blob) => new X509Certificate(blob); + + [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + [MemberData(memberName: nameof(PfxIterationCountTests.GetCertsWith_IterationCountNotExceedingDefaultLimit_AndNullOrEmptyPassword_MemberData), MemberType = typeof(PfxIterationCountTests))] + public void Import_AppDomainDataWithValueTwo_ActsAsDefaultLimit_IterationCountNotExceedingDefaultLimit(string name, bool usesPbes2, byte[] blob, long iterationCount) + { + _ = iterationCount; + _ = blob; + + if (usesPbes2 && !PfxTests.Pkcs12PBES2Supported) + { + throw new SkipTestException(name + " uses PBES2 which is not supported on this version."); + } + + RemoteExecutor.Invoke((certName) => + { + AppDomain.CurrentDomain.SetData("System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit", -2); + + PfxInfo pfxInfo = s_certificatesDictionary[certName]; + + X509Certificate cert = Import(pfxInfo.Blob); + Assert.True(cert.Subject == "CN=test" || cert.Subject == "CN=potato"); + }, name).Dispose(); + } + + [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + [MemberData(memberName: nameof(PfxIterationCountTests.GetCertsWith_IterationCountExceedingDefaultLimit_MemberData), MemberType = typeof(PfxIterationCountTests))] + public void Import_AppDomainDataWithValueTwo_ActsAsDefaultLimit_IterationCountLimitExceeded_Throws(string name, string password, bool usesPbes2, byte[] blob, long iterationCount) + { + _ = password; + _ = iterationCount; + _ = blob; + + if (usesPbes2 && !PfxTests.Pkcs12PBES2Supported) + { + throw new SkipTestException(name + " uses PBES2 which is not supported on this version."); + } + + RemoteExecutor.Invoke((certName) => + { + AppDomain.CurrentDomain.SetData("System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit", -2); + + PfxInfo pfxInfo = s_certificatesDictionary[certName]; + + CryptographicException ce = Assert.Throws(() => Import(pfxInfo.Blob)); + Assert.Contains("2233907", ce.Message); + }, name).Dispose(); + } + + [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + [MemberData(memberName: nameof(PfxIterationCountTests.GetCertsWith_IterationCountNotExceedingDefaultLimit_AndNullOrEmptyPassword_MemberData), MemberType = typeof(PfxIterationCountTests))] + public void Import_AppDomainDataWithValueZero_IterationCountNotExceedingDefaultLimit_Throws(string name, bool usesPbes2, byte[] blob, long iterationCount) + { + _ = iterationCount; + _ = blob; + + if (usesPbes2 && !PfxTests.Pkcs12PBES2Supported) + { + throw new SkipTestException(name + " uses PBES2 which is not supported on this version."); + } + + RemoteExecutor.Invoke((certName) => + { + AppDomain.CurrentDomain.SetData("System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit", 0); + + PfxInfo pfxInfo = s_certificatesDictionary[certName]; + + CryptographicException ce = Assert.Throws(() => Import(pfxInfo.Blob)); + Assert.Contains("2233907", ce.Message); + }, name).Dispose(); + } + + [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + [MemberData(memberName: nameof(PfxIterationCountTests.GetCertsWith_IterationCountExceedingDefaultLimit_MemberData), MemberType = typeof(PfxIterationCountTests))] + public void Import_AppDomainDataWithValueMinusOne_IterationCountExceedingDefaultLimit(string name, string password, bool usesPbes2, byte[] blob, long iterationCount) + { + _ = password; + _ = blob; + _ = iterationCount; + + if (usesPbes2 && !PfxTests.Pkcs12PBES2Supported) + { + throw new SkipTestException(name + " uses PBES2 which is not supported on this version."); + } + + RemoteExecutor.Invoke((certName) => + { + AppDomain.CurrentDomain.SetData("System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit", -1); + + PfxInfo pfxInfo = s_certificatesDictionary[certName]; + + if (OperatingSystem.IsWindows()) + { + // Opting-out with AppDomain data value -1 will still give us error because cert is beyond Windows limit. + // But we will get the CryptoThrowHelper+WindowsCryptographicException. + PfxIterationCountTests.VerifyThrowsCryptoExButDoesNotThrowPfxWithoutPassword(() => Import(pfxInfo.Blob)); + } + else + { + Assert.NotNull(Import(pfxInfo.Blob)); + } + }, name).Dispose(); + } + + public static readonly Dictionary s_certificatesDictionary + = PfxIterationCountTests.s_Certificates.ToDictionary((c) => c.Name); + } + + public class PfxIterationCountTests_CustomLimit_X509Certificate2 : PfxIterationCountTests_CustomAppDomainDataLimit + { + internal override X509Certificate Import(byte[] blob) => new X509Certificate2(blob); + } + + public class PfxIterationCountTests_CustomLimit_X509Certificate2Collection : PfxIterationCountTests_CustomAppDomainDataLimit + { + internal override X509Certificate Import(byte[] blob) + { + X509Certificate2Collection collection = new X509Certificate2Collection(); + collection.Import(blob); + return collection[0]; + } + } +} diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxIterationCountTests.X509Certificate.cs b/src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxIterationCountTests.X509Certificate.cs new file mode 100644 index 00000000000..15a39d05755 --- /dev/null +++ b/src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxIterationCountTests.X509Certificate.cs @@ -0,0 +1,26 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Security.Cryptography.X509Certificates.Tests +{ + public class PfxIterationCountTests_X509Certificate : PfxIterationCountTests + { + internal override X509Certificate Import(byte[] blob) + => new X509Certificate(blob); + + internal override X509Certificate Import(byte[] blob, string password) + => new X509Certificate(blob, password); + + internal override X509Certificate Import(byte[] blob, SecureString password) + => new X509Certificate(blob, password); + + internal override X509Certificate Import(string fileName) + => new X509Certificate(fileName); + + internal override X509Certificate Import(string fileName, string password) + => new X509Certificate(fileName, password); + + internal override X509Certificate Import(string fileName, SecureString password) + => new X509Certificate(fileName, password); + } +} diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxIterationCountTests.X509Certificate2.cs b/src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxIterationCountTests.X509Certificate2.cs new file mode 100644 index 00000000000..6e4697f4065 --- /dev/null +++ b/src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxIterationCountTests.X509Certificate2.cs @@ -0,0 +1,26 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Security.Cryptography.X509Certificates.Tests +{ + public class PfxIterationCountTests_X509Certificate2 : PfxIterationCountTests + { + internal override X509Certificate Import(byte[] blob) + => new X509Certificate2(blob); + + internal override X509Certificate Import(byte[] blob, string password) + => new X509Certificate2(blob, password); + + internal override X509Certificate Import(byte[] blob, SecureString password) + => new X509Certificate2(blob, password); + + internal override X509Certificate Import(string fileName) + => new X509Certificate2(fileName); + + internal override X509Certificate Import(string fileName, string password) + => new X509Certificate2(fileName, password); + + internal override X509Certificate Import(string fileName, SecureString password) + => new X509Certificate2(fileName, password); + } +} diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxIterationCountTests.X509Certificate2Collection.cs b/src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxIterationCountTests.X509Certificate2Collection.cs new file mode 100644 index 00000000000..40b8ac11da8 --- /dev/null +++ b/src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxIterationCountTests.X509Certificate2Collection.cs @@ -0,0 +1,44 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Security.Cryptography.X509Certificates.Tests +{ + public class PfxIterationCountTests_X509Certificate2Collection : PfxIterationCountTests + { + internal override X509Certificate Import(byte[] blob) + { + X509Certificate2Collection collection = new X509Certificate2Collection(); + collection.Import(blob); + return collection[0]; + } + + internal override X509Certificate Import(byte[] blob, string password) + { + X509Certificate2Collection collection = new X509Certificate2Collection(); + collection.Import(blob, password, X509KeyStorageFlags.DefaultKeySet); + return collection[0]; + } + + // X509Certificate2Collection.Import does not support SecureString so we just make this work. + internal override X509Certificate Import(byte[] blob, SecureString password) + => new X509Certificate2(blob, password); + + internal override X509Certificate Import(string fileName) + { + X509Certificate2Collection collection = new X509Certificate2Collection(); + collection.Import(fileName); + return collection[0]; + } + + internal override X509Certificate Import(string fileName, string password) + { + X509Certificate2Collection collection = new X509Certificate2Collection(); + collection.Import(fileName, password, X509KeyStorageFlags.DefaultKeySet); + return collection[0]; + } + + // X509Certificate2Collection.Import does not support SecureString so we just make this work. + internal override X509Certificate Import(string fileName, SecureString password) + => new X509Certificate2(fileName, password); + } +} diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxIterationCountTests.cs b/src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxIterationCountTests.cs new file mode 100644 index 00000000000..18ab1381a02 --- /dev/null +++ b/src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxIterationCountTests.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.DotNet.XUnitExtensions; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography.X509Certificates; +using Test.Cryptography; +using Xunit; + +namespace System.Security.Cryptography.X509Certificates.Tests +{ + public abstract partial class PfxIterationCountTests + { + private const long DefaultIterationLimit = 600_000; + internal abstract X509Certificate Import(byte[] blob); + internal abstract X509Certificate Import(byte[] blob, string password); + internal abstract X509Certificate Import(byte[] blob, SecureString password); + internal abstract X509Certificate Import(string fileName); + internal abstract X509Certificate Import(string fileName, string password); + internal abstract X509Certificate Import(string fileName, SecureString password); + + [ConditionalTheory] + [MemberData(nameof(GetCertsWith_IterationCountNotExceedingDefaultLimit_AndNullOrEmptyPassword_MemberData))] + public void Import_IterationCounLimitNotExceeded_Succeeds(string name, bool usesPbes2, byte[] blob, long iterationCount) + { + if (usesPbes2 && !PfxTests.Pkcs12PBES2Supported) + { + throw new SkipTestException(name + " uses PBES2 which is not supported on this version."); + } + + if (PfxTests.IsPkcs12IterationCountAllowed(iterationCount, PfxTests.DefaultIterations)) + { + X509Certificate cert = Import(blob); + Assert.True(cert.Subject == "CN=test" || cert.Subject == "CN=potato"); + } + } + + [ConditionalTheory] + [MemberData(nameof(GetCertsWith_IterationCountExceedingDefaultLimit_MemberData))] + public void Import_IterationCountLimitExceeded_Throws(string name, string password, bool usesPbes2, byte[] blob, long iterationCount) + { + _ = password; + _ = iterationCount; + + if (usesPbes2 && !PfxTests.Pkcs12PBES2Supported) + { + throw new SkipTestException(name + " uses PBES2 which is not supported on this version."); + } + + CryptographicException ce = Assert.Throws(() => Import(blob)); + Assert.Contains("2233907", ce.Message); + } + + [ConditionalTheory] + [MemberData(nameof(GetCertsWith_IterationCountExceedingDefaultLimit_MemberData))] + public void ImportWithPasswordOrFileName_IterationCountLimitExceeded(string name, string password, bool usesPbes2, byte[] blob, long iterationCount) + { + if (usesPbes2 && !PfxTests.Pkcs12PBES2Supported) + { + throw new SkipTestException(name + " uses PBES2 which is not supported on this version."); + } + + using (TempFileHolder tempFile = new TempFileHolder(blob)) + { + string fileName = tempFile.FilePath; + if (PfxTests.IsPkcs12IterationCountAllowed(iterationCount, PfxTests.DefaultIterations)) + { + Assert.NotNull(Import(blob, password)); + Assert.NotNull(Import(blob, PfxTests.GetSecureString(password))); + + Assert.NotNull(Import(fileName)); + Assert.NotNull(Import(fileName, password)); + Assert.NotNull(Import(fileName, PfxTests.GetSecureString(password))); + } + else + { + if (OperatingSystem.IsWindows()) + { + // Specifying password or importing from file will still give us error because cert is beyond Windows limit. + // But we will get the CryptoThrowHelper+WindowsCryptographicException. + VerifyThrowsCryptoExButDoesNotThrowPfxWithoutPassword(() => Import(blob, password)); + VerifyThrowsCryptoExButDoesNotThrowPfxWithoutPassword(() => Import(blob, PfxTests.GetSecureString(password))); + + // Using a file will do as above as well. + VerifyThrowsCryptoExButDoesNotThrowPfxWithoutPassword(() => Import(fileName)); + VerifyThrowsCryptoExButDoesNotThrowPfxWithoutPassword(() => Import(fileName, password)); + VerifyThrowsCryptoExButDoesNotThrowPfxWithoutPassword(() => Import(fileName, PfxTests.GetSecureString(password))); + } + } + } + } + + internal static void VerifyThrowsCryptoExButDoesNotThrowPfxWithoutPassword(Action action) + { + CryptographicException ce = Assert.ThrowsAny(action); + Assert.DoesNotContain("2233907", ce.Message); + } + + [ConditionalTheory] + [MemberData(nameof(GetCertsWith_NonNullOrEmptyPassword_MemberData))] + public void Import_NonNullOrEmptyPasswordExpected_Throws(string name, string password, bool usesPbes2, byte[] blob, long iterationCount) + { + if (usesPbes2 && !PfxTests.Pkcs12PBES2Supported) + { + throw new SkipTestException(name + " uses PBES2 which is not supported on this version."); + } + + CryptographicException ce = Assert.ThrowsAny(() => Import(blob)); + + if (PfxTests.IsPkcs12IterationCountAllowed(iterationCount, PfxTests.DefaultIterations)) + { + Assert.NotNull(Import(blob, password)); + Assert.NotNull(Import(blob, PfxTests.GetSecureString(password))); + + + using (TempFileHolder tempFile = new TempFileHolder(blob)) + { + string fileName = tempFile.FilePath; + Assert.NotNull(Import(fileName, password)); + Assert.NotNull(Import(fileName, PfxTests.GetSecureString(password))); + } + } + } + + internal static readonly List s_Certificates = GetCertificates(); + + internal static List GetCertificates() + { + List certificates = new List(); + certificates.Add(new PfxInfo( + nameof(TestData.Pkcs12NoPassword2048RoundsHex), null, 2048 * 3, true, TestData.Pkcs12NoPassword2048RoundsHex.HexToByteArray())); + certificates.Add(new PfxInfo( + nameof(TestData.Pkcs12OpenSslOneCertDefaultEmptyPassword), "", 2048 * 3, true, TestData.Pkcs12OpenSslOneCertDefaultEmptyPassword.HexToByteArray())); + certificates.Add(new PfxInfo( + nameof(TestData.Pkcs12OpenSslOneCertDefaultNoMac), null, 2048, true, TestData.Pkcs12OpenSslOneCertDefaultNoMac.HexToByteArray())); + certificates.Add(new PfxInfo( + nameof(TestData.Pkcs12NoPasswordRandomCounts), null, 938, true, TestData.Pkcs12NoPasswordRandomCounts)); + certificates.Add(new PfxInfo( + nameof(TestData.Pkcs12WindowsDotnetExportEmptyPassword), "", 6000, false, TestData.Pkcs12WindowsDotnetExportEmptyPassword.HexToByteArray())); + certificates.Add(new PfxInfo( + nameof(TestData.Pkcs12MacosKeychainCreated), null, 4097, false, TestData.Pkcs12MacosKeychainCreated.HexToByteArray())); + certificates.Add(new PfxInfo( + nameof(TestData.Pkcs12BuilderSaltWithMacNullPassword), null, 120000, true, TestData.Pkcs12BuilderSaltWithMacNullPassword.HexToByteArray())); + certificates.Add(new PfxInfo( + nameof(TestData.Pkcs12Builder3DESCBCWithNullPassword), null, 30000, false, TestData.Pkcs12Builder3DESCBCWithNullPassword.HexToByteArray())); + certificates.Add(new PfxInfo( + nameof(TestData.Pkcs12Builder3DESCBCWithEmptyPassword), "", 30000, false, TestData.Pkcs12Builder3DESCBCWithEmptyPassword.HexToByteArray())); + certificates.Add(new PfxInfo( + nameof(TestData.Pkcs12WindowsWithCertPrivacyPasswordIsOne), "1", 4000, false, TestData.Pkcs12WindowsWithCertPrivacyPasswordIsOne.HexToByteArray())); + certificates.Add(new PfxInfo( + nameof(TestData.Pkcs12WindowsWithoutCertPrivacyPasswordIsOne), "1", 4000, false, TestData.Pkcs12WindowsWithoutCertPrivacyPasswordIsOne.HexToByteArray())); + certificates.Add(new PfxInfo( + nameof(TestData.Pkcs12NoPassword600KPlusOneRoundsHex), null, 600_001 * 3, true, TestData.Pkcs12NoPassword600KPlusOneRoundsHex.HexToByteArray())); + + return certificates; + } + + public static IEnumerable GetCertsWith_IterationCountNotExceedingDefaultLimit_AndNullOrEmptyPassword_MemberData() + { + foreach (PfxInfo p in s_Certificates.Where( + c => c.IterationCount <= DefaultIterationLimit && + string.IsNullOrEmpty(c.Password))) + { + yield return new object[] { p.Name, p.UsesPbes2, p.Blob, p.IterationCount }; + } + } + + public static IEnumerable GetCertsWith_IterationCountExceedingDefaultLimit_MemberData() + { + foreach (PfxInfo p in s_Certificates.Where(c => c.IterationCount > DefaultIterationLimit)) + { + yield return new object[] { p.Name, p.Password, p.UsesPbes2, p.Blob, p.IterationCount }; + } + } + + public static IEnumerable GetCertsWith_NonNullOrEmptyPassword_MemberData() + { + foreach(PfxInfo p in s_Certificates.Where(c => !string.IsNullOrEmpty(c.Password))) + { + yield return new object[] { p.Name, p.Password, p.UsesPbes2, p.Blob, p.IterationCount }; + } + } + } + + public class PfxInfo + { + internal string Name { get; set; } + internal string? Password { get; set; } + internal long IterationCount { get; set; } + internal bool UsesPbes2 { get; set; } + internal byte[] Blob { get; set; } + + internal PfxInfo(string name, string? password, long iterationCount, bool usesPbes2, byte[] blob) + { + Name = name; + Password = password; + IterationCount = iterationCount; + UsesPbes2 = usesPbes2; + Blob = blob; + } + } +} diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxTests.cs b/src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxTests.cs index 1132d8d85a4..f05849a64eb 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxTests.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxTests.cs @@ -1,14 +1,28 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Microsoft.DotNet.XUnitExtensions; using System.Collections.Generic; +using System.Reflection; +using System.Text; using Test.Cryptography; +using Microsoft.DotNet.RemoteExecutor; using Xunit; +using System.Linq; namespace System.Security.Cryptography.X509Certificates.Tests { public static class PfxTests { + private const long UnspecifiedIterations = -2; + private const long UnlimitedIterations = -1; + internal const long DefaultIterations = 600_000; + private const long DefaultIterationsWindows = 600_000; + + // We don't know for sure this is a correct Windows version when this support was added but + // we know for a fact lower versions don't support it. + public static bool Pkcs12PBES2Supported => !PlatformDetection.IsWindows || PlatformDetection.IsWindows10Version1703OrGreater; + public static IEnumerable BrainpoolCurvesPfx { get @@ -448,6 +462,65 @@ public static void CollectionPerphemeralImport_HasKeyName() } } + + [ConditionalTheory] + [MemberData(memberName: nameof(PfxIterationCountTests.GetCertsWith_IterationCountNotExceedingDefaultLimit_AndNullOrEmptyPassword_MemberData), MemberType = typeof(PfxIterationCountTests))] + public static void TestIterationCounter(string name, bool usesPbes2, byte[] blob, int iterationCount) + { + _ = iterationCount; + + MethodInfo method = typeof(X509Certificate).GetMethod("GetIterationCount", BindingFlags.Static | BindingFlags.NonPublic); + GetIterationCountDelegate target = method.CreateDelegate(); + + if (usesPbes2 && !Pkcs12PBES2Supported) + { + throw new SkipTestException(name + " uses PBES2 which is not supported on this version."); + } + + try + { + long count = (long)target(blob); + Assert.Equal(iterationCount, count); + } + catch (Exception e) + { + throw new Exception($"There's an error on certificate {name}, see inner exception for details", e); + } + } + + internal static bool IsPkcs12IterationCountAllowed(long iterationCount, long allowedIterations) + { + if (allowedIterations == UnlimitedIterations) + { + return true; + } + + if (allowedIterations == UnspecifiedIterations) + { + allowedIterations = DefaultIterations; + } + + Assert.True(allowedIterations >= 0); + + return iterationCount <= allowedIterations; + } + + // This is a horrible way to produce SecureString. SecureString is deprecated and should not be used. + // This is only reasonable because it is a test driver. + internal static SecureString? GetSecureString(string password) + { + if (password == null) + return null; + + SecureString secureString = new SecureString(); + foreach (char c in password) + { + secureString.AppendChar(c); + } + + return secureString; + } + // Keep the ECDsaCng-ness contained within this helper method so that it doesn't trigger a // FileNotFoundException on Unix. private static void AssertEccAlgorithm(ECDsa ecdsa, string algorithmId) @@ -476,5 +549,7 @@ private static X509Certificate2 Rewrap(this X509Certificate2 c) c.Dispose(); return newC; } + + internal delegate ulong GetIterationCountDelegate(ReadOnlySpan pkcs12); } } diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/tests/RevocationTests/AiaTests.cs b/src/libraries/System.Security.Cryptography.X509Certificates/tests/RevocationTests/AiaTests.cs index 89882f4de5a..753bec3b88b 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/tests/RevocationTests/AiaTests.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/tests/RevocationTests/AiaTests.cs @@ -53,6 +53,41 @@ public static void EmptyAiaResponseIsIgnored() } } + [Theory] + [InlineData(AiaResponseKind.Pkcs12, true)] + [InlineData(AiaResponseKind.Cert, false)] + public static void AiaAcceptsCertTypesAndIgnoresNonCertTypes(AiaResponseKind aiaResponseKind, bool mustIgnore) + { + CertificateAuthority.BuildPrivatePki( + PkiOptions.AllRevocation, + out RevocationResponder responder, + out CertificateAuthority root, + out CertificateAuthority intermediate, + out X509Certificate2 endEntity, + pkiOptionsInSubject: false, + testName: Guid.NewGuid().ToString()); + + using (responder) + using (root) + using (intermediate) + using (endEntity) + using (X509Certificate2 rootCert = root.CloneIssuerCert()) + { + responder.AiaResponseKind = aiaResponseKind; + + using (ChainHolder holder = new ChainHolder()) + { + X509Chain chain = holder.Chain; + chain.ChainPolicy.CustomTrustStore.Add(rootCert); + chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust; + chain.ChainPolicy.VerificationTime = endEntity.NotBefore.AddMinutes(1); + chain.ChainPolicy.UrlRetrievalTimeout = DynamicRevocationTests.s_urlRetrievalLimit; + + Assert.NotEqual(mustIgnore, chain.Build(endEntity)); + } + } + } + [Fact] [SkipOnPlatform(PlatformSupport.MobileAppleCrypto, "CA store is not available")] public static void DisableAiaOptionWorks() diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/tests/System.Security.Cryptography.X509Certificates.Tests.csproj b/src/libraries/System.Security.Cryptography.X509Certificates/tests/System.Security.Cryptography.X509Certificates.Tests.csproj index 18b91ea8472..07c332c411e 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/tests/System.Security.Cryptography.X509Certificates.Tests.csproj +++ b/src/libraries/System.Security.Cryptography.X509Certificates/tests/System.Security.Cryptography.X509Certificates.Tests.csproj @@ -35,6 +35,11 @@ + + + + + diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/tests/TempFileHolder.cs b/src/libraries/System.Security.Cryptography.X509Certificates/tests/TempFileHolder.cs index 4ce70ccbf44..a6efa3a1f19 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/tests/TempFileHolder.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/tests/TempFileHolder.cs @@ -20,6 +20,13 @@ public TempFileHolder(ReadOnlySpan content) } } + public TempFileHolder(byte[] content) + { + FilePath = Path.GetTempFileName(); + + File.WriteAllBytes(FilePath, content); + } + public void Dispose() { try diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/tests/TestData.cs b/src/libraries/System.Security.Cryptography.X509Certificates/tests/TestData.cs index df98b93190c..857fda868d7 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/tests/TestData.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/tests/TestData.cs @@ -2910,5 +2910,1221 @@ internal static DSAParameters GetDSA1024Params() yJpx+jD1MsjIEXIn5jtjXdUHd0JJmHWAyHdNzmhXrXC7JLnj4ri7xMAV3GZGDpAn YvvL0LiXzFyomg== -----END PUBLIC KEY-----"; + + public static readonly byte[] PfxWithNoPassword = ( + "308205DB0201033082059706092A864886F70D010701A0820588048205843082" + + "0580308202F106092A864886F70D010701A08202E2048202DE308202DA308202" + + "D6060B2A864886F70D010C0A0102A08202AE308202AA3024060A2A864886F70D" + + "010C010330160410286B4EFF0202AFE16583E50C3EB8F38F020207D004820280" + + "C3452B3850AE69FCC0AC426FF3A0421477813259C128D643452219EEF71EBCAB" + + "5E7054B7A195E3F945222864CA37D8F67DDFA9136A93CD7FEAD86F00D4179F1C" + + "557253253C6235295499729C564DE2CE30E131C0D9B3E1BDBB211F8FA9E78B7B" + + "088C63137DF44CF50C293E082E7C57A8D0CB0404D1F5B9D1491F4EF9045181D3" + + "8D528C61F49EB3F1CF11ABB60270CBC10AC4BAF115A5AB52EA22FE4406743695" + + "7DDC1BFEE0C6BDC097BDF092AC6D11CABAE497FC10564E7E7797BC6028CBD75B" + + "1A2339329D439F6557B3CEB77489467FC8990EE832D48E2FF65A7BCB20E2DBBD" + + "F81C762F688E2EE43822CF9DEDE11914DD982FAB2AC141496D912396F6F67E3C" + + "D04D0617F8EC2BE6D35AF9860C384DB8C21FD0B00494FA3188983E6200DE90B3" + + "E6E662C5B07AB202A1B9C3F10F03B88E677EC7BDC2873AA4DFF873DCD714AD39" + + "42C33E63442A855C709F58063D836F8CA77DB9D208F3DB2552D7AC611409E8BA" + + "942BE520D9B4951AB844892D123DF550BA4F22D255069AD77E6C14D730128FAD" + + "3736551CDBEED2022417A948B1BD2567C39DFB561F251C45D2F4B5711B4AC82A" + + "09226403432FEEEEAC5F54590CC2EC7925768651ACF42C32A114ED133718FB1A" + + "9FB0DCC35C10640226F7587BD4EA67C10EF963113D03988C82B3A0B43B1B60ED" + + "BE0A7CBCB6422CD9695BF206A190E8EA6F87E2FABB33549081EFA7A8B04CA044" + + "9DF52E133556781511CDFCBDC55B487DA51C8D476FB635896FD0C71754B2EEE9" + + "A395F355F4A56CCB8CE75D65F73AE8DE80215EA7CA9129FD90EC48ECF26828A6" + + "0E471FA5F34471AD1C21AD200E16C4E4E99FA55B5CF75BC4BF68D1A975E8276F" + + "5EBD47EEB21DB06092F51AEE6BDAA2CDBC9387620A2B3983247E9AA93252D49A" + + "3115301306092A864886F70D01091531060404000000003082028706092A8648" + + "86F70D010706A0820278308202740201003082026D06092A864886F70D010701" + + "3024060A2A864886F70D010C010330160410127070F8C0D10011CBE0CC8489A3" + + "0C71020207D080820238C151B340B678AE8CAD6C6B11E0661E91FD1F4107F0DB" + + "687F039362D88AFF382E3557A75157D8A6D93F0777AD41D7520D32916677699A" + + "EC3DAEE462344BF18410EE07E83811EC26569FF9CD8D13A77F387D6E7C5C21C1" + + "6BC9936DB1B8AB614A8B4B6F9975E4A0A5DFCE29EF14E833FB2526805901A782" + + "724AF6BA2A80E93A4C4BA07B1C1319169E200A4B7AB100AE2CA135512919120A" + + "1D1AB57EF6DED00144F87D051391676D205196ABB4B211698BF137436D6E39D6" + + "719737B66AD2E76D5766D36E87108D79145021C77328A9F2ADDF44EC2A95EEA3" + + "86DCA32FB53D0AA92FB5C5BB7B49CB1F1755ABF195C7274702681C616C21BB05" + + "817B5FD344FC25CC6145A4FFE36F4D5BC131434E6C44BD14769EB08FBDA0D1A0" + + "6DCF2D061FA4A2FCC45A30125680507AACEE7903ABA0C1D36395925A82741797" + + "CF93A11F249D7E7D8228F8F6AFD03FB317D1F2BDB319C0AEF15E19E9DB1067B1" + + "A6CC12CA458C33BAB31C3F275C45A956F71CFF939F393EC7D20E13B397E64263" + + "702B54DD228D0E1275B39A77B3B1A28EFD5C7DF2643CAF7AAF8574988CDF4112" + + "E057F715331F6E75462E6C948BFB92C5BC81B84FBB47FB97AEB3D8C228388B94" + + "CDFA0E2A48F05A32EA9F2CDFAE2B0CEFF815531B148C358ECE1D23F7B793A1FF" + + "ECE491E990BDF231756600B87FA2F7F3AD2C2AA2F6DB42FC6D62766F28F60436" + + "FFA4993C87BE6631D7CE6C06C5B7AE7218450C504ADB401B9FBA5FB2FC6A8289" + + "B42D51B4E1AF159AE7F3A63BA8644C8C5A99F108FC25A27DE54E268AF8A259D9" + + "F6E3303B301F300706052B0E03021A0414AF311074EBABE699402460BFFFE14E" + + "4D7314FCB4041469835268466D1390373566F7034C4736346CD17D020207D0").HexToByteArray(); + + internal static readonly byte[] Pkcs12NoPasswordRandomCounts = + Convert.FromBase64String(@" + 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 + mSdzI1U6Td0CASo="); + + internal const string Pkcs12NoPassword2048RoundsHex = + "308209CF0201033082098506092A864886F70D010701A0820976048209723082" + + "096E308203E206092A864886F70D010706A08203D3308203CF020100308203C8" + + "06092A864886F70D010701305706092A864886F70D01050D304A302906092A86" + + "4886F70D01050C301C040887A8C4D7DB154CC402020800300C06082A864886F7" + + "0D02090500301D060960864801650304012A041028529AA9F7079F5031C52A23" + + "8A23CD4780820360ED47A5097F8A6C7B6EDD1989CD19C67B8A59DBF6CD22F7B8" + + "36A4B8D9BAAD54666FA9F022CDF366BC1B4A47604C4A0B67C09F2DBB8F75D185" + + "B62DF310817E24FE71A47246831C58670A27A5693CAFC52EB730B7BC0CF00145" + + "A9E4D6784D3A49C524546415EA6448D991C5C83FACAA4C1FECF198DA5B8CA9B1" + + "09346B723238359CC18D1CC28B185AA3860B082086F9FD909F3BA3D94C9238BB" + + "CF8AF18C0A56E6A88E7E0F4F15675770C812F805604743B1E8E683FFEB3FA4C9" + + "9D2C6B00A858050DCFE12C0DB3471B678657C7E28C074277165D714FC4A6E193" + + "C118C676FD2B2F97B36D8EDAFC3332609F192EF98D3ACAF1EDBCB03A2DBB9B0C" + + "8AEF748A5BF66F1EDD9C7C8A81638D644F9ADC99DDD6BC7FA7FDEDFF044D47C1" + + "6F62280D80526D05F17D5DBB44209A3F27CF88B881227D5685DB6BAA22914D0C" + + "E0B01D9997F9A429B4294940BA75FBB08C7C7EEFCD77B7BAD0DBF3E418F4B551" + + "ACAEC537DDA914DD0BE933181A86B433640C1E10609D96D093544D119727D1F8" + + "49060303189EA33B8FF8950493909B0963EA4BC8999BE78D2D2F1315F96B24C1" + + "DE6A925C0DE3C862788B2AFC56BF343E63E1274D0B8652C6C49033E1B21AA283" + + "0AB2A1406291D215B799D8CB5CB6CA0D3B0458C51EBFB01207E96DA04FDE7C24" + + "F32E48A0B4E48EDE150B13D8B2B1D3B736BC4BA54F800DA9F980F7CB9F23B7DF" + + "8C343F980ADB0752E2978D4C1069337A631E15D945D8EB858FA6D1548C230269" + + "21D0413F13FD4C94A1BB8897040AC3CBF13DF42FFCA7D0CF76FF08C68893E45A" + + "061700E4BC3B005FDF4E8A04323B98D07ED037E4A341E49E43F2D2BABB0CE6B9" + + "4D260BF720A7B864DFB12B22D28F4992C91A16E30346252191EB60A06C23BB6E" + + "1FEAABFFCCD57C0A2516E8015E9B329C97D99704E653EBE04BBF26199B11A2B7" + + "E30FCBCD2C57A1389B0747E1B9896C6CED2C86D721DEE424120E0347A05B57F9" + + "19FA1FA334512C1EA43205E5B1A56BD1F490C5EC3CFEA17CF1E8EC4686DD6150" + + "0C420D03E6E807491B24ECB6E64F210BC8029399C153E62705E80FF358E1A705" + + "DE3EC20DD3AB6651EB51E7F7F2729ECB9BEF94B9E1A685555DC075453072AA06" + + "5C8C821033DB91D1DE64CB085E09721580FB01AEE2C105E62177D88E25B4EA54" + + "4605636CA3261107DF7CB8FB2661CBA0B855726F8F3F087B95EB257B523B007B" + + "45B9C71E030FBDCF3082058406092A864886F70D010701A08205750482057130" + + "82056D30820569060B2A864886F70D010C0A0102A08205313082052D30570609" + + "2A864886F70D01050D304A302906092A864886F70D01050C301C04083D689F19" + + "C613307C02020800300C06082A864886F70D02090500301D0609608648016503" + + "04012A04107F45F9CB7E9F7A54479C6B260310BF0E048204D0C37C420A86E386" + + "22F3EA79EFDA069F9A0542207ACC6EC2B7D497D06C2F0E20FC362F637C032D86" + + "72B9A0A393F0DE872B19668D37C35CBA4DA6407D80A1A61998BEDBB01713D41D" + + "741C5D4A03B877B2CB6F66295B3C7E3955AEE9F8BA250086355CA8D340850825" + + "28F3544F9DFFD19D764DA15E6D178E7D8D843E0E8FB0FBF5CD9D6203644FD6D7" + + "88754AF0372BEC11938406A27D76EFEC6974F92982F2F2D212256DF3122CE631" + + "7C079B14D9B14D8E8AE31EBFB76754DB6D5497DC3F7DEDB73DC2E65F722BB3DE" + + "D1D217628DDC42EFD646501B8B8E085996D87F11E3B29B85FBAD0AADF71A391D" + + "92F11DA38286F7C57D12F3923D334D3EE186098B88A77869514DE08FF1D09675" + + "4D6FB2978CDFCE051F7A0AF5E27BC8B0DDFD9230FB292EDF4F8893BA7C1CF8C1" + + "B91B527E13B93D0B32E7A130D829D928281655FF93A60220194777EA4903B577" + + "EE7D12FD585D69ECBE52192BC9A0731444122C13ACD45926DFE13E7F151BBC71" + + "2787DE41A1319B974DF20F0E28A2B8C247553C6A98B52F545723ED67F36DB626" + + "7BEDBE8198AEADF2AE0B177F3F2B61A53AD5EBD99F10BBF8F578AEBC780EF766" + + "F512118263A7775BBAB8D1E7D2B8E55892A59BA4E4DA74C63A90319589096AED" + + "516AC29F6DD666BE867C6E411F0A63D8EBF0A4F8F591D8E16F106DE0A63F001D" + + "373B0A72B3BFBFE27B1463F8A01CF5A4BC81988DCEE84A76ACFF3F27BB205708" + + "848F0555686E0A650280EFC7517BB433742961DE1E0B08D43EC64BBB6B2847A0" + + "01FAA219D470E553A8BA05479DDB4B3C0FE50BE45C7126084AD249B521733477" + + "473B687BBB75D47C3AEF41C72BF7612FB4ED8D9EF51CBEAD26279AE07C3A8151" + + "7E65FC8A77712D8EEE8994F1632157C3F1403DB0FD2A95C0A89D323BD9205AF0" + + "E228DABEA7EEA182B8D257BEF9D704CA0E9FAB1027F49BCB8D75C2969447EC4D" + + "59EE74B762092664AB68DB5390C8E76AD91399DA5473222DF32C96D519FDB21E" + + "3D2EB1C6D98B3A3525D1E92504E29A0DFCE59B0B982D0A8EB845A8BA4DF22CEF" + + "CEEED25773E51C5C1FC0F96A697E24995342FF82D7573479D342B7E41AD2FBEC" + + "BB6F728F8D3D964C09F9FD39239B58AA91269DEA87755C6CAF9F6F876A1EBCBF" + + "9983DF2D6BBFF81D180435B65DE95C7BD41062F123B7CCF31897CC7028F6DDED" + + "EA747F069AECA55637B9848674AB1CC4A61944C274B500E37924F7E394DCCECB" + + "93052BCA45AD66851E9CDD4194470BC2F91667C6E1F696B89A219C45CDAF1752" + + "CC8D95875EF343E90765CA366CDFC55F6D72D2590FBC47BFFA9F45BAD5C4D50B" + + "A89F117F20A934D84C972A15AC4DE8F7D105B1E0AE214BFCA16BC44C4D4A096E" + + "699057ECB1E3D9D6933CC8AB9D9E93A5194BB39FE289E6FC121A564FC049C99D" + + "6B6BFE5B11E8292CEF1E4E80453F805D5BA49BB26EBD84847F1CF238335005FE" + + "2552A972DF84618E59201798DC1FAB60188DCBF18C6B30CEC921D40B76B9BBD7" + + "458819427D0444A2421D69CE1E23D335EB6C327F8145DD3FF25EE740F7896A24" + + "AEAB3E65FA9209C18BCE8A1D28EEF053611170E3B1CB43F583D6084AD40C0035" + + "E053CC6133E67B18F12D508BA43B79E1B2D1EA0CC2B91002BFA2D286DB6CDEB3" + + "796449B33D6DA4E47CD326B8C123228E68D822DF1B8A50520EAB8A2319227415" + + "4F4EA2C604A2274AB881D6B4EC36E0C3F5104A0BBE51E061E4F09A425F797BA7" + + "545D45CB4567A39D923125302306092A864886F70D0109153116041444BBC698" + + "3FD4DB3AD40E15D39784227F2A2E60A330413031300D06096086480165030402" + + "010500042053B736831F5398BCA4DD020714A2E9B46FA9BE273F81DB5A13D27F" + + "482282DE4B04089ECC39D621BAA9ED02020800"; + + internal const string Pkcs12NoPassword600KPlusOneRoundsHex = + "308209D20201033082098706092A864886F70D010701A0820978048209743082" + + "0970308203E306092A864886F70D010706A08203D4308203D0020100308203C9" + + "06092A864886F70D010701305806092A864886F70D01050D304B302A06092A86" + + "4886F70D01050C301D04082BF1679DE99B425702030927C1300C06082A864886" + + "F70D02090500301D060960864801650304012A0410E60AE5FBE308F1D6E6820E" + + "18F85D357380820360E334B918A3971F37CFCEAAEFC215BD0773462CEF830E5F" + + "73D28190E78FA023A2EB377952BEE5927A0FBAF841C96059E4B0111880DCD6CE" + + "619B4B07DCE651642F29AE978AFD15EABE55D5E2AC94439294F15F4E4A304D88" + + "54B04555E30D251D7BD6B53F0584C5293E78F9427861EBF90BA0E41C00A4210D" + + "5208DD27C45E5C964988F00206399AA256D19103E391765F0E4E89319AA8FDAA" + + "F79856ECF1E6F5DDC9629E778446A0DB25FCF541D4815E66967124BB751ADF2F" + + "10DD658BCD76CD7854561E161FDF4300F84C5E04B91B3FE52436BBE2D7DFA2D1" + + "5D9C6E853D4F221F833FF85A985DA2010050FDC17B6013DF16B71B1FE181401B" + + "447A7CD78ADB894F310119600EBD79872CEE05254F141FF4AE317B4B19089943" + + "1FF692246DDC9D042C517FBD389EE2AC9A8DDD7214BBC010FD7A90A325DE4224" + + "D833A55B8118C5BBB003304956C98A4CC1A91EEF29BBE6DCC4F5353EE53065B4" + + "2B0011E291B81C9A8D43CF436F2A47DEB40C21547CA2E416A61740E9DC5107A0" + + "1913612DB720770788894EC2531BE2676F3CB9AE5C73D5AF35261F41D474A565" + + "0DCCE0A9A63EA6A4BE80E0726EF4C1A5805DC8888330D2973402BD0BB4017BA9" + + "D83355DB97A9EDD04D727A1A3FF796267E56494E2A89B0705EEF88805BB23D98" + + "05207982C2B43CD3FB83E8C65EAAB0DA8E5FB85D9821CACA20BD21311BF0E3EC" + + "4F309375D7AC89E9B32B1B2EFB51D45FD5F88AA066A05A775311857A192B7DFB" + + "200FF7F276C284655E30164543A53B3463BF6F8B037452544BA86764B4ACE00D" + + "F2C26B18D9F457153585432201F578F74BFE9A4F8010C3B4973C865CE175485A" + + "3EEE47538C73EDF5E3DB34D814B6525351D03648948561760CCE3F4DFE423ACA" + + "78E1F82C78476528BD35C8D02C17AD41E9796F048BFC4CCC15FE11139C1A104E" + + "469368C654FEFE69139014ED6B30E6CAB30DC7FCF1490BC91C50F1716CF348FA" + + "7EED577F7AE25219163BC1BF378271F9E676CB99227BBAE64FF8D9BBA2FBA69C" + + "6A045CD70675809F9C3EC1DD30A4542C36E4B5B52F982E8369300C7D036144E8" + + "004804F186F2F54385BBD5ADE939F2CEABA8D785DF62D54348CA76D94669C350" + + "07BE6C9A9A9CB263A9A098157B39C6B8E1368D9D7F9D9524D5CD3B9FA1EFEB9D" + + "44AFA24F2536C3A70E19DF07B7B0A68385D8572753A251648534B953717CAEBE" + + "19EABF8E36F039A2503082058506092A864886F70D010701A082057604820572" + + "3082056E3082056A060B2A864886F70D010C0A0102A08205323082052E305806" + + "092A864886F70D01050D304B302A06092A864886F70D01050C301D04088064D4" + + "32AC75560902030927C1300C06082A864886F70D02090500301D060960864801" + + "650304012A041028618CDEA80BF226578A2DA0DEFB48F9048204D070F86CDE3E" + + "25FB88321EB1D0B9E8BA8736C1954E7EC2AD3BB3B4DBFAF6ECE268FF693008CA" + + "DF785473709F6ECE9AA8F93019C5EEF6E557DD5587C3B3A85B77A3FB1871F58B" + + "0316B4A4210BC2856E5B4AF46B3BFD114AD8FEC7195CAA4D8FF578EC0A945A63" + + "1000981A56525F8AFC6F140F5DEE2193C7DE62579890ACAAF056A32CC6E7CCFE" + + "2839DAF60FD881C0D34BC450DD7F0F9378A695F27F547A73044444163670294E" + + "578FEAF5627865F297147ECBD16E45C128697063D16FF4A773ECFE2978124C06" + + "A7728C6495CC35C957A635F213D237C8D64B425ECEE868CD1B901CCBC3AADC1D" + + "CDFBB433195EDA5CBC6C11D048D7DB7C5A0443828483DADA0C63FC4FB3234A3A" + + "6F749428F371121389BE52DD5F9532B8CB86E096ABAEF67865ED7A6D9AA0AFB3" + + "98361237819188AE5592D65B450A9F99191D1E4007FA4C7067E55B495A224435" + + "E6FBB891D5CC84D929166B807C8114E26D6125C7B19B0ECAF55676F61127A75B" + + "56740D00BA582A4412301E3220EE58FC1A55B578EFB90F398B9940CC23581A29" + + "804244A0C37D4661113DF6B43FD77CE00B0E9C4AACB28292FB20DCB12FA461B1" + + "07E853C057867C5ADC6C8D21A812B05A20ADD09F6E6ABEFDC45DD1CF7C64D7AA" + + "0408CA24D1B7014F2C960E8ADD356FD13B75448287677B23F48F7B527380709D" + + "4ABB09A5EB3100068F55CC4A194166BE75F32C52F3031F69EECD36A5400C0769" + + "E5C5DFAB81F1480C916872169EC34B49646C9AAC76909EB8B49CFB9ADF07ACB7" + + "5B051AFF623955F1CB0D5E11154576497306D92CF1A19C02D0B10D219C956DBB" + + "47DA7F24C554D0AA6D71C5DB4E966606B863445F39DD955AA062DF78BCD0C509" + + "000BA379A4BA1FEAB5A9D3EB5FF40B3C85C9450B1E06F79A2670DE7EA799B741" + + "28B67A2B1062391F78B00958497948F8F1133096EEE10E761080CC55928D1F13" + + "AF835DC7098181CA2D27DEEC292C40CB969AF15BC8F82E31A224BB24F04BDDD1" + + "49C57688FC1867E6CA995A4D8B2D72FEA76ADB9E36775EC6994EC346150B26F7" + + "40491EA804C176D9C8852308AF4849A88F2D1C93E948C848D22B0122CFB5C7C7" + + "E848DE044480DCBB6E282285BD00CC8445E6992190B13764337CD226613F2CF5" + + "EB5750A7FBE079B68FD3950E8D3CAC9E579BAC61AA7D52F9F4194C4DA59F07BE" + + "40EAB8F3104D0C70E92AA0273DD3C0CE1901BC9780B5762C833974D193539627" + + "61AD01E3BF23C6C7941372CD042BB05A897E18519C497236DF21ADBFD5507414" + + "E50725AAE16A5078464719FA61C426BA4DF9B42EC2D84824F2505E5745446BF4" + + "CDD8444FEC1E505665C46339054D8CFD6A54CA9C1275C96BBFAF456BEB77491F" + + "71D2D002B2F7805D44DFDAE37C0C4FAD680A7B0DB89AD006208FE01284050AE3" + + "3A21CF566FD2627B1A86A1C2402658083B08998D37234B00CAD3C1F91A54CDA8" + + "57A777BCE878E9902297E4A8128AA2D7D58AD5F491717F9B3C10775F55783641" + + "D052BBF2B69B15D5CB78488731C091E5B7D3EF768D8CA1F2089F30ACBE014566" + + "F566A69CDC09268F2D25B9E9E60FF08742EDE0E85735FB4D4FAD8464B163542F" + + "CE3BBEA4F6DC2869F48B8212013226BDC8B520F74349E85244C7DE0D84F9C4AC" + + "DF8B7C5929267A2CF2AAB77FA7C46BC6A983FC70991002EDCBCDC647ECF289E1" + + "BA930216325D5919290260BA192E8F3E1EF136D4BA18DABF7F2A6F87701EEF98" + + "B66CEF645CA90BF8B75AEC3125302306092A864886F70D010915311604143809" + + "23C6F251CF50C47C7670DEE626FD1708A70E30423031300D0609608648016503" + + "04020105000420AD0EB570ACFB8357A8E99B17672353CFBA69C76FFE5B6BC113" + + "05577F12AE24040408D04E60444B79672302030927C1"; + + internal const string Pkcs12OpenSslOneCertDefaultEmptyPassword = + "308209CF0201033082098506092A864886F70D010701A0820976048209723082" + + "096E308203E206092A864886F70D010706A08203D3308203CF020100308203C8" + + "06092A864886F70D010701305706092A864886F70D01050D304A302906092A86" + + "4886F70D01050C301C04088FC6C10979E6D39802020800300C06082A864886F7" + + "0D02090500301D060960864801650304012A04109EF63F4518B8635FE54FA2D5" + + "2EC0C19880820360B9DEB42B1F8B8F4E58C9CB35F871A99821775275D604A14B" + + "498689CCFA1D8855C1BCB7C07528145C3D77903BCC27E9133041782018D6C1DE" + + "F094328772836DB17E5271F0A0B7D8A9BAAFA1086E95483DA5CE8519B4B911ED" + + "88FF0FC47AEB5924180D8B35083C5B3B44D2C8B7DBB2ECF5FAC710862B090D5F" + + "801932A0E56286DF0CAA10D7CB8243B88D7C2F619D06B233DF6D16060D392F28" + + "2C564ED685ED8227619694ED34050B76C8E28ED38B69C0AF9672060545C81B99" + + "EB6463BA8A786422322180C31D64FCEA249DB78C51CA5B84DBD8522A8AF531EC" + + "930A0A03BFA5CC7F84EE9F98819784D8E22237D524369F02D620B5AAD9C336C4" + + "737285305DC53A8C383453E0D278450CAE3DB2807DE4B0D5C6BAE4BE40370ACC" + + "5CB8D03644E553B0E98FDAAAAC00FDFDD102CF8ED916E22E686F30B575660B4B" + + "3C5BE7A1D3CC1D5217A8614F3BC80727671B13E5776988F7784A7E886C23C733" + + "A0C6A633D7FE8D7EC9ED9B2706B40373940BA8F9BD1BB7F8CD700384D06EC809" + + "21EE29DC45CD7D6EBFA1BBDECFAAA26AFDACB9E8C86450EF404BD3B60716E2E5" + + "1E943E1E1E595113C0EE3687493F252110ADCD4A44562BB3E2A6C682500C6591" + + "F72542BF6953BDB94CA977925B636DCEA6A6BA634CE8E4A44387CD20566DD120" + + "E3096E99ABF83D88D12F6CC4117E422460414DD0F89982A080FBCA7669568865" + + "0E9A07087EAC27753AA5E0AB126093CC9391B7510541820C6DBFF07B790F6DD9" + + "699530BCF5286C9537A9024C0778BBB854EA5A9034B293A78F4FBD2F3C572538" + + "2C703E8CCDFC7C54CB28005E4C511F8C8EEE84E65415CD46680547A7B7BB72BE" + + "CE5432EB1C6EFEF308092C35667BEB7509594F75A6D06D35C5C12FBF1C331E59" + + "6A5BC1E4DA753E319254068B7EC7824BD8389E5379773D14BF664D1A75991CD3" + + "E4AD815CC9A131FA66765530E55362983D4AC316D055BE68E8052101EB36980F" + + "2E72F5A3442BC1302F1E9A721C7A8D7B56A6DB36477712FAB04F1C17F073F8B5" + + "279B441E35BBC7986E67C1D9C8AB6DB30AC045ADDEBACC29BE1AB6FC57EA41C0" + + "5F7CC21BD1AACC1D7B9F2B5155893CC11D512A6DFA5FCE72BEA259D381B57019" + + "6ABE1C186B1B445B1B0B03DA596C3A5AC0252D026CB3F5DE42C06E81AA7A7029" + + "F249EFDA7581862AA29FE1F4E8ECD9F1BFB673119ADB0D369A28A2E3962BC265" + + "3BB1453BBDDE09CF3082058406092A864886F70D010701A08205750482057130" + + "82056D30820569060B2A864886F70D010C0A0102A08205313082052D30570609" + + "2A864886F70D01050D304A302906092A864886F70D01050C301C0408CB7AC3CE" + + "BA6EA01002020800300C06082A864886F70D02090500301D0609608648016503" + + "04012A04100E253ECAD79E0856D73A2CE9A3D48101048204D0D617F9EFF71270" + + "B09B3287BD6014E3DE6C8AD23BA19156ADE125B0324CA30B758DB8EEA9689A25" + + "1586E6E50A0C3A5DD975A2BAA6B571FF1C9C78E361F0ADBF4E9B4F7BB57B2728" + + "621E3B113C5ED339ABB89AD31F803AE2C976C1F0B96ADD7D2FD54E27C490D3AE" + + "220202531960B57B029379188C3613D6B1AD6F03526E1BB23AEC273C8F6E017C" + + "01358356EEB8D1273B5B114129DBAD60E367D70C92B65D38D0EB56130864F708" + + "3A43B7E3118362D21CD032D21CE94E6266809A69087313767E0D9BE736333AB2" + + "9D737E313302C6BEC5124023A22C395EF4A0AD165D344B329A09E5E4593F4848" + + "323FAE51B283EF0DBDFB951BDE62A0C7FC2E6419A412E86680F6414E154DA560" + + "2B4B46B836AABB3DEA03B1FB12110DCC6BA1C0FFE902CA892E4827955E1488B7" + + "AACA0FA0EBE8B8ADDF425CD9AA65B407503D0089D74B809310C737923386B86D" + + "DA357654C4A60285C31BF9C2BA22862D7774EE2FD8AA92008F678CBA8260F04A" + + "561081FA8818CC384307AD0AB4C3BFF86D1BEECC136D0595CC6E816B51C0888D" + + "EB4251FDFA5C02FC6D9EE0C60114406FB7391A149756497A2D88207075E2A528" + + "E021B68820F68F89F4F6A5709A18D440E09B5BF239D4ED36E8C3358DC7890033" + + "D9A0761A0A062734B709144A5B1CE9296480E66E0800B62FAA881F70AB89823C" + + "D513BAC42346758EB3EC982B7F8B4808DCCEB64CF854A18FB0E2D0D3B29FDF63" + + "B60C21A614621183F643BA56BBD0713AA5444EABD1415FF9CC2ACA80B70256CA" + + "CB059949760257128AFCAD51E8B9F574DCEA9BBA42344BACA4D96F7EFAA5AF64" + + "EF01119D34E971D4837C3633C202FA47892C59B37A88310F9CD2C523F0A4F952" + + "BF925A80F2DF0A813283739416DA1885EB3DE5AF04FE6C828C1AEEACBBDA7B82" + + "A00F3505A56C88FBA0537B1B4F7B7F54C1551A5F5279DEB9DFCA2C2EEEBF1D75" + + "F60DE8777703B7AB67411E5DD4478E7430E34CF1D0E0FBA7AFB124D40FA3E04E" + + "5D737D9C1CFF0F8B1CE7E2D4F99C340BB4360FCC285610A44247021BF1CD338A" + + "DBD4C9CFE0C1685AED1A4EE01CD34A9BD446F0E69F16EB395A6AF8E4710A13A2" + + "75D2B102AE38DC0204A6331155E70A0B73440759FCB89CC5E0A2012082696A16" + + "7B97FD90FFE53349D9883FACECC2B7237B28468C6637ABDC47EB595B82662703" + + "C9A8BB3AD8B7DEFFA323EBA092C8BEC5CCE3C5BDD10AABAA872A7620B4888351" + + "EDAC82D0E7DB5585C5B8119E300F8CF8B24C62EB397B9069038AFD69FBF1305D" + + "83FF499E203873F45559868DCFD813A5FB5BF4EC695A7463C6B0A2A8487B09FE" + + "B58BDC0BBBAA377909DC88F03FC3E058D80E22E54840E8803BCB78440C44E6E0" + + "1A17519F78C2C89D965C9B984C96FCFE5DB22ABE51241F88A15BF0DF20936072" + + "EBCDFA465182F41A0025E877A308045D09FF988F122AE2639EC14601ACA00E59" + + "81C3E1B6C8123B8EBB2CF9936D9CF3C4A0A8A694E26E9FF6EED0B0544BEA6F08" + + "EEF5FFA27DC0FA3D169F51C42DCBC65C3BA935F6EEF2D78DD352206C0F5E0F92" + + "AB8A4284D67088C0587443242035C23786BD0A3C48452ECB44F4E07422DDC849" + + "099587763991C299C5BFE8BD14D6904516B31254C1176F191962B81FB5BF16AF" + + "B0E25980A0D069D9FABB11A053FA5D8CC71F7F825A2C96A87D7A6F21FC6D8DA5" + + "059F848F6AB5B85A04D1257218EE480444148F4B0A1BEA8CB4622A96EB9B4EE2" + + "A76F14B1CE25EDCFA23125302306092A864886F70D01091531160414B524C1AA" + + "CC976B19833DCC9739FEE5B240AD3A0030413031300D06096086480165030402" + + "010500042029A4ACD27A78AA6BF3B9114E19D1315E76BD450EDFDFE88F4E5E98" + + "2DDBFC734B0408D154718FB757EF5102020800"; + + internal const string Pkcs12OpenSslOneCertDefaultNoMac = + "308209180201033082091106092A864886F70D010701A0820902048208FE3082" + + "08FA3082036E06092A864886F70D010701A082035F0482035B30820357308203" + + "53060B2A864886F70D010C0A0103A082031B30820317060A2A864886F70D0109" + + "1601A082030704820303308202FF308201E7A00302010202146543F3FA4FA3B8" + + "75A1BFDDB3CC23ECBFEA736A00300D06092A864886F70D01010B0500300F310D" + + "300B06035504030C0474657374301E170D3233303432303137323530385A170D" + + "3234303431393137323530385A300F310D300B06035504030C04746573743082" + + "0122300D06092A864886F70D01010105000382010F003082010A0282010100D6" + + "C77692CB15D98788AF8C00AA0C626AE45015C8300364C0303F09A1D48DFF5599" + + "A3B8DEC49365E28274E2E33288ECE042322CF8B2697E760D0FB4E8894C209859" + + "9D7BCB39DE74596638D11C87F8245EB245AA0FFDDABC45F804158776B6A1980F" + + "13F4C87F2BDFADEFDA91C3628544BF5F328E5F1215B5F277F6C7B89413720B22" + + "9FA9DFD132A7CC187F88154D6C091841461D2E7C35F75C1A40BB99EDC3C3873D" + + "51C2F68F804F58C0A4FCBA8001F6B92825581B4A9391C6A770614F6BD82B39AF" + + "13094EE7E49DCAB7FA2C751533B358C874148BAB88B915FC99BB8C8F907A4317" + + "3FA14F3B26EF4FE5B014D107DF73E5A2FC0E9ED651CB376A78CB1177E5D83B02" + + "03010001A3533051301D0603551D0E0416041479B60678BEFC1E3784E8A780B2" + + "30A7E826DFD627301F0603551D2304183016801479B60678BEFC1E3784E8A780" + + "B230A7E826DFD627300F0603551D130101FF040530030101FF300D06092A8648" + + "86F70D01010B050003820101000ED62D8DCEF486F04C6047AB0C2CB25FDF1923" + + "7E46D1AD9C16139B8C0A0236EDB46582AE45EDF2E242947A81AEE2AF4BA9AA9B" + + "3297FDD76B1C7F235288802DA590213B4A5E7986B828E072665D2855860B86F8" + + "F625F2BF6111938C54563DBE8AAD21DA2A883F901CC2D7CD08DB113F3468384C" + + "388A6B07E4C301839D4F0E8BD38920FEEA4DCAC3ED817BE1D0F3BBAC45E772C5" + + "41B0819DA4F0EBAFB952C082A57714758394C07416EAB0B53ACBEFD2F2E2138E" + + "B91CE02F4F8E008C976CDBED10340B79B9F9FF8CC94C65EAC274C4A08E1347B0" + + "21268E581CDF1730AE9DF3B959508262DED10B040A1D8346F0F544A2BBBA7454" + + "C2B2A7218B21B64D82B8C04A0F3125302306092A864886F70D01091531160414" + + "D222A8E9C8CF876416F9A2132202326C1AE63C203082058406092A864886F70D" + + "010701A0820575048205713082056D30820569060B2A864886F70D010C0A0102" + + "A08205313082052D305706092A864886F70D01050D304A302906092A864886F7" + + "0D01050C301C0408E0AF915D08BBD72002020800300C06082A864886F70D0209" + + "0500301D060960864801650304012A04100CA536131D2DDA95F84830C4E47E84" + + "4A048204D0075FAF61AAE642CAE276A7AED857DEB08094880EA949F763F54DA3" + + "B1C0CED0D383B3B305F5D4C033B33BCFA08385F58BE862048F739B59C30AB3C2" + + "1B8C877D2056D27CD1A015AB8EAF86725CB5F2892C667CC02DE0AB215D4859F4" + + "A4DFF4C6B8187B4DB5DD2BE8217482148D0135E1B6B7784E7C8515FF4155D662" + + "5E742D45D3DDDA357BB7FAA90601773C96468F2E023242CD6B087CD0C504C124" + + "8D747BF0465F33EA2904682678CFE57B4FC9DD8162230F7C6980B399D793B796" + + "08668B7FEF17430E128AADFAF37F7610924845327A631F51B4AFDBA3D08C2408" + + "8C6059FE0495003E210F53E616CAAD669954A7E517DFF203746DA1A6693BD23F" + + "3DFF096DF050DB68AF7E4213F2A40D03C274C3E1F224B66A3481001C445E99DF" + + "F5EAE97A9E7C34D035A89DDAAF982794E2BAB630EB61F96399B891F460463052" + + "CD6176E6561DDC60C9FE476D125758AD3EAF9747818A4F963181928E79FC667D" + + "396EFFD95CFF25DEAC00E0B1A4092E0F0AF9132116A78C75B3306469F64B536B" + + "FD6130B756899A7FBC79EB11BB0F124A8BF08AD818923ED9D1F93A79C1C1DEC6" + + "58B8859794A3C02F9299901F4303CFFBECD354BB77FB5BF63146B8F85C4C0F81" + + "85A7A6C8A28C51C33340DBB2204AFC70D4D79AD2C35514E4BEB413D519A12288" + + "29E7195A730A1A65FF9585E32F91F232DA23BDEB2DFDBEA5377AB9E053198899" + + "B140F816979D53F738601782C7CC24E881CF337F5CF50C24EBE2ADAD74FCD523" + + "2E620B8F144252BEE0B0FCC08AB239526B1DBE7F6C3D1FC8184F60B8B30C64F9" + + "B42F5B674C475A4D088C81C8D9102118273C6DB632CF7E127E037D6B317DE6FA" + + "C7B2752F1173851E3C099F40F207B0EF57BF80C73C224B70D0D975C15A8A2193" + + "2E34EF1113C48EB8258968B37D2358216E6302192C6FB6A68B325D7B731CDABC" + + "4D1FE7A4EA25AF60F5B224FB8BC0A3DB8ABED63FC1B91FB43AA4ACCDB32B46F8" + + "1441CBE62B1C38A4FC1E76E2419579890A10906044E18CC1D06A1866EAE98B78" + + "2BC5503BE5E24638C79FD804809F69D8019B77F498A36CEAF1582DAE245CE949" + + "BE493751FDD232A02AEF72DAF9B527AA29BF8C0B0384DB29BECE1A1E3B81E681" + + "00C047A22E73ADD5ED5B19BD922279BF8E0D4834B69408B5A9844B8421D6420B" + + "3BA243BEFBC2AFA74DA94D34B58BD827D59025438EF4E982E0BFA133F5EDB181" + + "FB5E3723CAF8BF0AFDDF20DF75A433850DFBBDAAB3FA7B61962A66A0AEEC1476" + + "B12A016CCC2B12C16AA8547D46B33F3B6008A65C165125BAD61345D9777E40DF" + + "232190FB47934E3B935B963DDE4717F4F4D1E932D1D7020226C0A2472327E16A" + + "F8E16DCEF37C52E58A65FA44842E5A323DD768322DD0F22BA1CDF9E54A3C3ABB" + + "7010A9E4C3D856719CD025C1EC7AE2DBCB8DE8ED68AC542797978C47310BB3B4" + + "D34A4244B3D0D01338A2EF8A43DF1180C01BA03AB9A382C888912BBBE541F8A8" + + "7C0CDE2EC2405F67AC22049410E2AFD9A8E4B8A836055C399A5422DB375A7520" + + "99A947C933DEFFC26532F399D08978443C6D040FD29C5842B6E0A8235D44012C" + + "6783AA66ACA31FCCA155AD6429BEDCABA71398B287AFFCE96AC8ECC36CD222C6" + + "7140E144656A0D8FCBDDBF5E96390DBB7C7C093EEBD8DFF0BDB68568BFE77D7A" + + "A7A3B6C94CD9737B8FF3C4F9684062E175AE9EB8DAB5B8956EAFB3A5EC84C9C7" + + "376F5F4B588E60875F3654A15899FD3734455366083125302306092A864886F7" + + "0D01091531160414D222A8E9C8CF876416F9A2132202326C1AE63C20"; + + internal const string Pkcs12WindowsDotnetExportEmptyPassword = + "30820A06020103308209C206092A864886F70D010701A08209B3048209AF3082" + + "09AB3082060C06092A864886F70D010701A08205FD048205F9308205F5308205" + + "F1060B2A864886F70D010C0A0102A08204FE308204FA301C060A2A864886F70D" + + "010C0103300E0408865AFCE404C9F4C7020207D0048204D89F814ACB055451B7" + + "7FF858162304D57C3B3393283C3DE8F81B4A2264501B47665EDF7A830B064DA5" + + "DBCBB95A1DE88E07E50681AA732A800FC006617317B0D461450EB0A8CAF73F7A" + + "26B96510A47BE05034301B33954B6DC2E581D00369DACC98C189FE2ABCDEF057" + + "3E5A04D0199EC35F0D401CF314F714D6720220315E13ACE3B982258A94642407" + + "88BF9899E4B631B577293E8C8BA288D459DD6B158AB1C8C585D8ECAD23E3F49A" + + "99EE4B64027DB0A5E5241EC4F2B7D614A2F213F50CB97BCC8C64E1194CE6103E" + + "E21CEB1F83C8A8C4D3CB4F0E76CC8482F34AB8F3D42386E061C72C4A9D040076" + + "09C86331483F0E19A3C94BD2848E708C4B6D07DFF70F839BD7D39A269B4985C2" + + "025FC6230D08999B5121C71FD9E11E5CDB694C6C5C1EEC5D92E9296A8BA59902" + + "82666A494BDFA916EE9FDA34EA64A0877868DDB61A5F63E3EFC54DE52629A2E3" + + "FEB9D302331C4693711AA3B3C8DBEC5E44F4EF28E40C6B2C6F3C6861F270C87A" + + "210F5BAD2C05E43D2D93D5D349D7A60A5002E11F78E402294E77C946DA9F8F59" + + "F51E6BFFD1E322D95E3E49CEC25FE338F579B910B70268EAE76763A368125663" + + "E0B14F84C502A70EDF05D9C4A2257742E2F52C80E01A6A9FFC21E2E231DD94A0" + + "93D2819AF8261C7A2DB6659CC3FB237B8992FDA7242836A9F549555FDF55208D" + + "1E5E2B13B18D776A606941C9DE54B560101289141BD864160EB2C382DEC0AF28" + + "B9037FF80ECBD0189F1A2D22CC395637AF046D62E90220EE6630957422EFAD6F" + + "2F6FDF425B8B9F713368CCA5D3CE9C12DD6EF61B12074FAFAF87F3E59A42D8FF" + + "41BC8CAF09B5E79E3AFAD9832DED992F7A8441307379DA4225EBA0ED9E357664" + + "615FB53B349EB5AB1C2EF450B6338442D938A0D9C52CE38862015F11F1F805C5" + + "426E4AA33E6FF964A4E7F39F8088DB8A98821E737D1D974A70E3CEEC960B733F" + + "68A8C1A243F438DD6D4DD25924251242711343E6767359AF38655455D3058110" + + "73CC04DC656DFDDF7C3E30614D994C315E2CFAF63307C0327753817BDAA08C92" + + "5307B136DAC0BB5FA128AC7879501D00269E7C7B779DD5624F81C28040A2FE42" + + "0FED94C6086AB945D4A81F6F9547B73BF03A0F6E8E36FA629B7730A42D574EA1" + + "D6DD37AD7624AED6A5667500A3CC2CA45333A8E2872B390950EEBAFA7D98C3DC" + + "D16CD6F932C21D3C302DE8B161B85AC67A524855664A3473A541EAA9336E2FF6" + + "B4978BCCBE0C4D7D874EC424AA450B5C2802BD1DA7FF07493F947D2F0E202D3D" + + "6D43F57DA836EAED898B280BB374A23AD10E0F4399F549A76B166F80D0CF4ACA" + + "AEA53B7A7A13E85162FB48F54A7930D564E99F6345B030106D625FF92EC96E89" + + "921442A0F248C1681757D1C8638EEA75A1A5A2CA74F4DD8EE1EF114A56E040FD" + + "6DB11B4C6B542D8294C08B0C65B02DB59D883F52B3A5F0165E37EEA7999BBEF3" + + "669510A206A533F5A82DC52D4F6B54977D5F8AE493AE49BA10663862CF1B8675" + + "D42F8DC6BA3D748CFAF4DD75C870D782CC00F4D463EAF06E2BAFED47748225F5" + + "1756D089EDD71C090CD87225EE9D501848E4682460A23ABE5A4D0589ADA5105B" + + "14439ECAA937517FCDB35CA6BCEBD1190E71A793979F070B37A9AB2D003A00CD" + + "38D8EF194207FE53FD95D7C43F7C58718F0CE80588DB13B6828A1984D9DEBF0C" + + "1072FD2171AF46156A1685CD841830212B7C78CC1A40C9F92DB0017DCE853E1A" + + "83A9FDF792AD2935750D74298EC8051C3181DF301306092A864886F70D010915" + + "3106040401000000305B06092A864886F70D010914314E1E4C007B0037003000" + + "4200410033004500340036002D0033004200410036002D003400360033003000" + + "2D0039004200380043002D003200410039004200380034003300390041004200" + + "320032007D306B06092B0601040182371101315E1E5C004D006900630072006F" + + "0073006F0066007400200045006E00680061006E006300650064002000430072" + + "007900700074006F0067007200610070006800690063002000500072006F0076" + + "0069006400650072002000760031002E00303082039706092A864886F70D0107" + + "06A0820388308203840201003082037D06092A864886F70D010701301C060A2A" + + "864886F70D010C0103300E0408196DD4C6F976C7AE020207D08082035049FA3E" + + "9C159024F1821379145C29EFEE5AFEADC5F364CD86547A125BF22CDD99010BD6" + + "FD3A5CF0F028DC3E37E1DD509F83F2C13F59AFE2D3908B33EDC93488DBC0D091" + + "6A209039CC4A9B8E37F614FA6E877969796EE55B58699A65A98449F8F0ABA078" + + "50497075821CEA2BAE375092254407B1CAB99E8AC3AB1F582D13217E651E328A" + + "DBE6054A3FA4E0A6911B57A5F2651FC772D5A180FDA6846C089C6F0CFF7D3EFD" + + "22D04551B59F58BB605D9F6B99EF7F027082E200052A19AB9606DCD522386A98" + + "BF17FB599252052A69440DAC7D57187000D58E8902911A51422DE3BE79001A42" + + "0EBEE4D263A265D49D41432D6040D4D28734DD38288DD84ED32EBE281C361400" + + "7DA2D4751F423538EF6608F017C3E2B0A0E143ED066AA65A933D62F5872EC26B" + + "1C5CF29E264146DD6EC4A2A90DA88FCCC9E0E20F27373CAF09E9CBFB0D057094" + + "A9FB914BC194941A873D03139FFCA79405300FB46CBEA0070115271268C2196F" + + "C39DE444E483D6E36A973DC95775AAB3C81F766065A76EDDEA274C38F103B218" + + "5B57FBBB82F1316A6C023A51BF873DFE71E62259AA2FB6A5C4E4152D45D70284" + + "E08927B559F1706505277EC088BF91D3ACCC4E541AF1B7701DE69483B1CB64F5" + + "DFDCF259761E080D5C58ACD1BA8E3E13C52E4346D4743F4D7C5FC9FD1BD64D52" + + "0539B7E627A33ED2F5840A9D878AF88B32C5D5B8A8279662895A6DD129E8E511" + + "C5123885514D3E3FFC61C000DABC1648BC816746B3FCD00F967BF8F12B1FB18A" + + "E87A9972DD2B9D83A69E06FCACC37EF3CB6CEFE37D6EC68C40ABCDCFF9A91716" + + "6BFFFA54A54016089E4C008B0FCB9EDDBF2F426E6232D04FBA7C41F0BD044D52" + + "70B4B82D865D75BF8475970459E1BC28E9207189586944D84D1CDBB74EF25773" + + "9A2F070A9871B1072822A6614732A9D90B36E6B1F8B9DB190E0B65059601AFF2" + + "D19BF35C1C900E6D575DDBC1DA505FFBC19CE98E90741A898A207D254E236A89" + + "1826B66AB6E1D26AFAE6F59A70477F17D490DD1CD5673FEB65BB4C52CAAB02BC" + + "ADFDE6E483DB58C24BC3E596E451BB70FB425CD2010861D60CE726F9067659CA" + + "907134542C069E52AD359E2C300FE19AB08E343614AEBE1B5584D258F1713927" + + "4FB671EBCBA8B11CD4E35564B518A840D0DE69B54E39F762F3821E5C6EF5C2FE" + + "9CD9D62EB1031AD5D191B95F2B303B301F300706052B0E03021A04144BB56BD6" + + "06B405745EC53A2F4AE4598F557ABFF60414C984B699CDE84E8ADC55A7291E5D" + + "FF09EAAD2394020207D0"; + + internal const string Pkcs12WindowsWithCertPrivacyPasswordIsOne = + "30820A06020103308209C206092A864886F70D010701A08209B3048209AF3082" + + "09AB3082060C06092A864886F70D010701A08205FD048205F9308205F5308205" + + "F1060B2A864886F70D010C0A0102A08204FE308204FA301C060A2A864886F70D" + + "010C0103300E0408D10B4BC509135A33020207D0048204D8BC69D1EFA1BFF345" + + "14685D3FD6F4407BA4106DDBAD150E899E2C6BAE0B291797542F07376E797891" + + "16D8124259D24C3E753781187F3CF49FCF1994554A28E12A2AA76046692D3673" + + "00A6FA70D09BD1A0299FF481A2060879A4B34FD35ABA4C1EE87AADD95A42CA75" + + "50433F2BCF46548580AE0FBF839AC5C6BA984C9ED00EE8C164F701985B116C3D" + + "4771CFBC95B41CE2C61EA951A0B2B8297ED1A10E94F80640E3BC49AB004DD110" + + "7DB967921976B49AE1DC70AC7F3F1D85A4AD84D911E63BAC9DA9A620EE4CD74C" + + "512D240DD4937AD6718432C1CC39B00354945F80BC59B3A9C3A2CE80D17E4388" + + "88BD9A0C6665E1C4D31C676DB4135386704366E1650E457803E784C37658BEBD" + + "64C23338E6D5416587FD8460E2B04B2F9C884845481B93B6E3A829DA9C364ED8" + + "FCFE8DDF2053B8F8A6A3978B6F1760758C0124C87F04BF9D411DC3478E0A45CF" + + "A0BF342255F798D34C059B401B29962DCA862577C43D7BDD41A69BA220FD58E9" + + "5CD79B0F6FC43730E59E7C8709732B88C68F5BCD7156A75359D7AE38A71AC69A" + + "605BEC35038DEB4167EB989FA4D1B4ECBD25981C0C4D5D3109CF8C12863DF59E" + + "904DA26B0B03AF0CCB1D83F07A02338F413B6177DFAFBB4ABEC97FCF7804655C" + + "0697FAD4182358064A55AAC998B035D559C4496575676413152A38F079568272" + + "2E80AA090D9D974F8CCB59159F184B448ADCC3FE9E3032D64DFEC9405ED27030" + + "09A5BA3AA1A6A9D190DE7D068BBBE5F5A9220788B8052A81C1AE4343E1E17FE0" + + "0B8EB2D4537A97A9726E901FCC8F5B660AE84FF7EF1D2633FCE243DE56053C64" + + "52B1B0C8E73112B34C4DEDF9ADE21BFF9217B341017945D73B6B2670926AA4C0" + + "FF1EEE23EE56C8650CF0861A338F645B4859DB37281B4D655BE084D5FEAD1B8D" + + "15C77FF3EA96CBBD098C4E05F718FA81BBD8D423D491DA5A42C7919D14BC0C66" + + "D7F2FFF8102F2207D7866B3952A15B3EF96E59B8B0AFE59668AE4BBF8A75C0F4" + + "39F3096C3B9B172074C37CE8C0335BA90CED4C78A35EAE6BEC26FCEC69AA6470" + + "518A9131E0BDCE14604CF7C1DFB7C6CBC90C0147EC64417418F877045F0C947E" + + "16168035DC404E2EBD1C6B9BA0347F011AFAF908FF0A1D8FEB85DE87BA2F8CC5" + + "BBE29F4AD3FA4F2F16BB282DC801B817DBA5D00A71A83ADCD228DC03DDC477C1" + + "1693D7C9F179D1ACB1C13F6CFFBFBF7504A31BDF719B35E7A25B116EFAE68F96" + + "6AF7A9B545DCD3C9FE9FDA171E28E46A5FA749F81FD8D87FD52D4795F4E28554" + + "3B3C2289264EA9F5B1DBF0797F7795638E2BEA075F3AAF04C119329F43D9788A" + + "98E22784CE45D3F0659CFF73C55379156A56F75D3CE6BBA7F11F949CD61F9ED6" + + "9D84ADC7A41D67E64C2FCF532CFE4BA2D31400A8DBE70C4344790FFB9F353245" + + "8967D45FE4C6BAA588534AB8A43BB1417DE16D7413DB778698BDB75906BA8E22" + + "7C9221B2B44D358908BBE0C0F2F004BBCA5EA8986169C1EB59B6C8C9C254037F" + + "D44375DF38AE1AF5BC23485CB6FDCEC1C0CF0B8692B4E0A00EA549D4E4697924" + + "0CF5A90137D4E12ECC7F1966E6817CB1F06673EA7D51F462289E08B080257281" + + "30D738CAABFDA23821DCD9CF25452857E3EF237B661338E44A0C8C474944F265" + + "0FE693A3B677EC99A647CAD574E85605800B1BF305B779DF5ACFE21329E1B4D8" + + "09B9CC96363574E387403DE8B57A636D731108EF9501075547E412D22475C053" + + "AC21B74B24ED7AE7C23E1235E93F58D73181DF301306092A864886F70D010915" + + "3106040401000000305B06092A864886F70D010914314E1E4C007B0037003900" + + "4100300039004200300036002D0044003100440030002D003400430046003600" + + "2D0041003800460044002D003800420046003100360043004400320039003700" + + "340032007D306B06092B0601040182371101315E1E5C004D006900630072006F" + + "0073006F0066007400200045006E00680061006E006300650064002000430072" + + "007900700074006F0067007200610070006800690063002000500072006F0076" + + "0069006400650072002000760031002E00303082039706092A864886F70D0107" + + "06A0820388308203840201003082037D06092A864886F70D010701301C060A2A" + + "864886F70D010C0103300E0408CC0493121813F19A020207D08082035041716C" + + "8BF56E445181DCC9560D5AE27F850E9F87928D642B9C3264C2991F3BC05818FF" + + "30EF2D88C20F7E8F3453BF925BBCBBDE8273F5EDAA719D979B468DB9A02B38FA" + + "FB3A852F1CB828B69AD64B92DB29B0275255E0E9E2A1D82208B9388ED4075E7F" + + "18EFB6FEE20A3F1A440245BBC01C71DEA4AEC041C6BC2B7B108E85C1636F8C98" + + "2D2F860EF6B87C8C2705C14F4EBD351A36112BB26EF542EB4CD89DAEA112817D" + + "667B44AC99FBCEFC2164AC9D15A5CE589A61E0AD01F5C4467BD0835E23B41D48" + + "8122061A2E547CFCF38ACBEAEC0DA94290BB0CD52EFE15F5E0AAA89000E04437" + + "2B63787DC5C88392258C58C12BA1E63EB6A8D69ACF662BABF63714D99410C419" + + "D167820182988F5EE810A4C3F76D95057F0772F80E4E6B5F69CC58226DAC747A" + + "34311F509FC06F8055A83895E08520A88F74AC118C8F5FFA94DD6DDA74FAF779" + + "2B2A9B105079654A209D981E4C9954B3EC64E45681629DFC08E03B3D5FDF9461" + + "2A82365F2B959FADC808244ECC80A31C931E0E74DB4AF6864BD7AA90C33EE7E3" + + "432C41C756479927E1D80E241C59CF7BD5F1C2C3ED3376B2C1595C8C28A30937" + + "4E092FC99863A02D3C88E55AE43C3DDF83D8729D5CCAD761AF84C16E44F575AA" + + "67AE08CE9F8BC09C0A67C4C53B964A747C2505BDCF20690D8094F5AD58667CE4" + + "23BEE3383D9FCCC522F17304EF55B27B2DFF3CC4347537B7FCA30ADC16274EF2" + + "2DB9BFDECD5F44D55F8246D21EB64BBCA141BC5A8B62F999CBF06553490B6265" + + "68C3F61B060B0A04AA7A758D5C33155AA453564BA9CABE511C6D4C351A49F914" + + "3B80877542D9E65DEE2DE4AC2BC7A4997EE657FA4B885E3606D1F84D6977E758" + + "EFA84F7097A18330A3A222E7EAE434AD8D472127C7457CEC10602C4E0A4F0B72" + + "1968D8E0019EB5D77EF5B1EFF02D4A6CEE9BB28EDDD72D623FE9295126082631" + + "BE3A95DB414758B414448CB401EF0763BCCE74C83D93D45C2512977C35DEE3E9" + + "8A9D7AB96CAA0EFE7DDB8BB7AA77427151B88087FC97579A39D8A2AEF93741A6" + + "2C02E951ED1C3A172FC366253000AD457CE3194DCAC4DE13297D138A2EB007D3" + + "667F72FD0CE169799D85B85E474D06A28EBFB4C166911EAD43A70DB60A7FEC30" + + "4A6931591F13F3D029409548002D873551ABB2873BA3E16411E7E55CB693088C" + + "2B5DBB5F6861679BD1C2817A73303B301F300706052B0E03021A04145FA3D2F2" + + "D00A66EA4DFB51D5DE4D316276BCCDC00414FDBF473E8C4EEE8CC4D8DF166E6F" + + "6409A8F0EEDE020207D0"; + + internal const string Pkcs12WindowsWithoutCertPrivacyPasswordIsOne = + "308209CD0201033082098906092A864886F70D010701A082097A048209763082" + + "09723082060C06092A864886F70D010701A08205FD048205F9308205F5308205" + + "F1060B2A864886F70D010C0A0102A08204FE308204FA301C060A2A864886F70D" + + "010C0103300E04083EE6D2E1BADA3F12020207D0048204D8B84EA7E2CF71A281" + + "7828C34AA3005FEE52146EA713B5C3AA7958278B35FDF64AE8B998E3D87EA25B" + + "54B5319CF4390C812F7EE71D10CD3C70851AD81C690DE0326D0FAD71FF3D5038" + + "223988DAE31EC0060B6C2C5C9C74B08BE8EE3B78FED2A04AF83D38AD11AE8DF7" + + "8F7E5E1E447CDDDD0D9DF2AB10C4B8A90AF6E1152B6A7BE2BEDFFB4BCD8FDF3B" + + "D100114E75760396304BBA8C2AA19C430C9913028B422D5A74AE1429940D9B55" + + "DB9225604C5C4FD9B162A921E62BBCBC268470B84BC3BBB383A2C9BE7E178C0B" + + "2593D617D1466B95E57E90E30ADB7E08F6B0753B8B9981C49537B9B80D98BEFF" + + "350017130F360095156BD5F2F8963572F1B78A9B08B67642BB09FAEE48877259" + + "3383A830F3EB080210F39F5C28EA7892B8E6D8D6831A1DB33EE2B7A5BE758C65" + + "8837A6D1CB4383B47FDE181BB1F043C403567EDB66EFD95F585BC8DB248CD0B1" + + "909763DC9E3F46203C6FC61004962FA6799248E5E7F5B7A131D720F24056BD42" + + "30D1F5E6827B3025A66DF97436A02D441678797BAEB5135931B02A182C045B16" + + "9E8F86CB5871FD3DFC3FB573392230B70414A18BC792AC988993AE9AA2DAC5DE" + + "E09C87F60AA13637EC006ACA2525078E353497E1B242A5FA4BE57C764B24C4B0" + + "F5956D6067CD150ACEC57D4CAE982E782449588D5184961952A2871EC6FBCEB7" + + "E38DAED63C897808D7C2D499428E1EE04BDA40A287552493954A45941E684028" + + "2C964AB94D5A81E833EF28B3B7DF3698CE84595415001DE52ED85A6DB49D4329" + + "562C73F2AD51118A9E409FF96677C117B0528E725F55433798DB598F2B5B558D" + + "77F7703D1BFE6C24CBBD1CDC5961FFC45C139FE9855F93BA52A0183FF1C18742" + + "73CEBA04CDFD3270ADF3E20590E65E019DD6DE4FBD7C62DCEFDEC21103DC1C65" + + "078B76E9CC1DE6D33C4C6688A14CE938ACFEB25C8CD134C1BE439BFFCF8B9399" + + "8E8DBD7CFBD86D6CED0E1D1D8712913EABB7DD493209C61C39B757B329130562" + + "0E38EFC575C2FFC43A86300D5665C0B56DEE483762A623DFDEFF4627BCBD00CD" + + "3DC181AB22CBD3D602DFD379A223F6AC2134E47507501EEEAF33B06001C45B67" + + "C6DE14026B88CA0BBD44F941729FD3B9A078D801B98AAEC83A2431C1A7A1EB7B" + + "99051B4447256B2EC42A4E2917D6E7BE65FAB7866EB797F6ED4A988C57D4DCB9" + + "8C9236348A45BA717796E7715E734E2B585176100C5FFF37778EF76EE952CCE1" + + "5540E9DEC3E84E740694BCBE6E4108414319DC8E760852313C86B4EE03B8DF16" + + "8D00615FE20442C4687400E2436135C938E9167027799ED8890CC08788BD2A28" + + "41F0F2C1CF8CC2CB2950D3B2C93394017300C714BA941D356F8FA95FB5F82262" + + "B703F77A48E6EBE95DB2E7325F9248758578735EEE3BC0CC169FDA777A9FB591" + + "9A0007E0C191668F65714C359A872C14527B1A455305CE275135C7EB9F2E6AFA" + + "5F7FBB4994D0C2E8BF42EA9BC3581A7D70D3829B7D8204F2BC5AD9D24D7F3A09" + + "E0A0933D6532ADF03C500E11865C3138834AC110C513239E83606921929853F8" + + "D87FD51EEF9288178891AA5BC8A496E9BE44D4BFB83A3D435625DF3FF752E7FE" + + "FB8509D28E3A5E8BD5115FF0BBC2AB54DFB9DC8250478CC7E7A0624060B446A6" + + "4777501DBE0FF81EAAAC1F108BDD7E122FAE1CE7F326EBC697A016CDD1E364AC" + + "39FE901DF5D9E7A49225017DEA5374091232A47BE1147753CD60199268C70CA5" + + "ACFF5023B35FE76C92738BEBB1533FCB3181DF301306092A864886F70D010915" + + "3106040401000000305B06092A864886F70D010914314E1E4C007B0037003900" + + "4100300039004200300036002D0044003100440030002D003400430046003600" + + "2D0041003800460044002D003800420046003100360043004400320039003700" + + "340032007D306B06092B0601040182371101315E1E5C004D006900630072006F" + + "0073006F0066007400200045006E00680061006E006300650064002000430072" + + "007900700074006F0067007200610070006800690063002000500072006F0076" + + "0069006400650072002000760031002E00303082035E06092A864886F70D0107" + + "01A082034F0482034B3082034730820343060B2A864886F70D010C0A0103A082" + + "031B30820317060A2A864886F70D01091601A082030704820303308202FF3082" + + "01E7A00302010202140A49BFCB1DA91FFFDDECE6FBEA3EE7098A4FE4B6300D06" + + "092A864886F70D01010B0500300F310D300B06035504030C0474657374301E17" + + "0D3233303432303137323434315A170D3234303431393137323434315A300F31" + + "0D300B06035504030C047465737430820122300D06092A864886F70D01010105" + + "000382010F003082010A0282010100C53F2D0A6732510BD381F04F9EBFA1914E" + + "197754762CB256EB13B690D5F9A89E27D32FB92F706CB2615285BAECE16C93E1" + + "B6E2E205818A69EE99C2FF456F6EF117F1B414E43F71C0E78BEA69565683C9B6" + + "1CBB1247055FB88C758288CD70B22A1FC72E0B0EDE8A8A7B7AD50271B915DB06" + + "F2F7F6AC149439FA12049CFED26C916A80FA53E8DFCFFD7F2FD4FBF8A70B2BEC" + + "11342C977636C40EEB88F56B07337B2174EF51AD505B4283B876E98B93E8DEAF" + + "5CF4415BC828CDF39C34340921E16437BC7E19EEA44B73B26B594CBDA5729601" + + "C758F3476A221AE043E74975BD90D154643E319F9C253DCA9263A1C2526F7096" + + "A75C524A24B02F6DB13ECA5C43F9370203010001A3533051301D0603551D0E04" + + "1604143939D5CBE561A3E16AF98C385C4DE21C7745A7DB301F0603551D230418" + + "301680143939D5CBE561A3E16AF98C385C4DE21C7745A7DB300F0603551D1301" + + "01FF040530030101FF300D06092A864886F70D01010B05000382010100B4CA91" + + "1663AA6EB8B55B8BDEDDD4A07B1B0D0C79A819035BCAC086A01C5DFC64D2749C" + + "49FD67B20095288E1C54BC3A74FB7384DA4EF82CF5E66114373093DF1729DFF5" + + "95520975BE15C319B747F2209623245113C39B4A61909A6962A4CDDE832F6EE7" + + "DE15308DACAC4A6CFB1C0B0DA61AA9FCEE70441DC554F14A170BEFAD2BFDE032" + + "99C781BC115305E56E0BFF667B518DB0F16FCFA0B730B61EE01CF65EFE499C6A" + + "F5A67F9E20F7DFCD96A4B86ECA84F3E60AE94931B7A06C238BDE733BFAF131A0" + + "BD7D69D92AC75A4FA2EE300C1119DD05BF44BA05BDF1923DCAC9E372E5F2C155" + + "9EADDD2DB07B9BE2A984D2463E12262F058170C60BFC2646713C347D04311530" + + "1306092A864886F70D0109153106040401000000303B301F300706052B0E0302" + + "1A0414B7DC97F46A80902C720E8D237F10ED6FCC44ADB90414695EB196470870" + + "037CD616FBE42CC7469BA795DC020207D0"; + + internal const string Pkcs12MacosKeychainCreated = + "308209B60201033082097D06092A864886F70D010701A082096E0482096A3082" + + "0966308203BF06092A864886F70D010706A08203B0308203AC020100308203A5" + + "06092A864886F70D010701301C060A2A864886F70D010C0106300E0408365868" + + "CD387F42DB0202080080820378CB4B33E06FC54306174EC0AEB21E7DAB66B368" + + "4BFD1E6A2A01F894F38EAE1899CA23205BCD50A9525B125AD532084E6BD4AB4A" + + "5F80AD6FAFADF47AEDB18C9533E527833B972D8F8719141F9982E47AF3E7560E" + + "C34A3F248393659197480475AFE35DC804DA34C14043C67E0EB969FCEE09A933" + + "AC1DC8407F667744C395AB4FFCAFBE4E5553204228B32340692C68BEB99C4519" + + "DDF88D30E8CEF133AAFA77BE355A333C1BC395DFA9581B7F78A59B2089289CF1" + + "207266F8B237141013CA65EEF7DB2681ADC4FA7E36ABFAB2D424AAF83FED6039" + + "FB74BAA00D7D743E6DE29184656754EF99E927960717B414EA3390D62E3773E5" + + "BC82D8B0477ABB2338685951CB6471665E6EF8A7AF869F7A204DB5DAA1C34153" + + "EE9BEFADDE03082ECC0496EB245FE6DAD783F286AE114BAFC0DE20D435F1833C" + + "1FEE5021161D327127198D3BF568297C302DC2C37769DE8E7A499AE6CEF5186B" + + "168544996F5F4159676A2B9B887A335FDEDB14699C03629E204DF1FB5396B00B" + + "B40E20F8898BFCC46E400E32085C827346FC8E69F463938C9224E16EF2E892AD" + + "C37488389501A79A35EB573E915D62ADB2897543989D5105594A3CF3C38E0472" + + "FE8A66FB507498C09FE2BB191935C46A00C9DAAD4FC842DC3218182548D36B0E" + + "EA4114E5997F7FF6210352FE8FA2B0E5D0871DB8B65AF97F3748BD413FC55DD3" + + "B522BBA38113801D03577200126F18868314C11A0F2FB1BD5A4C60A7DAE49FBB" + + "B14A4B256B367289FAA891A1CABD58951531224B5BCDA6B61A17C7033BAB3D80" + + "E08CC0385C98E7B388E072060030B60796BF56A71B31163AB9827F3E3ED043F4" + + "F3DA619D8AB27E7887983152AF110EE552B5BC722FF0F021CEC1206A5C6D2B12" + + "3C5DF369DCC5A1C3C722B3A6767881F5142EE63D0A67866E8ED447884BD4A349" + + "A6DD2641AAE38624CE400E3D71A6420C0685F22422608FA143921EF661252626" + + "F54D743214531AD1F8D91B547E0EC24B9B01A97FD7FB2FF8DCBA530C221DE1F2" + + "0067196F2C1FAFF892E8E49803B33BAA291FC516E3FD5933E5DD0D2016F724EE" + + "E4E8644D7D93D80C9A6BDA84A10F79F50B52E6F76EA9274BCCE40D09A85F6072" + + "654645F4FA044719BEE24A04C2380A6596E17F1DF7213AD98019561E21DBC14A" + + "64D4AF49676113FBBAB9DF2C51E71048B505D1741B325B7AD2D202DC19D541B6" + + "DEDC7B57279C08EBFF5F588086295CE78840D8504D91577C35E9B49F164DAC31" + + "90704B2A7E3082059F06092A864886F70D010701A08205900482058C30820588" + + "30820584060B2A864886F70D010C0A0102A08204EE308204EA301C060A2A8648" + + "86F70D010C0103300E040814D5FF817FE6B0EE02020800048204C8E933D4E9FE" + + "25B62F989659649395ABCA2E20D6784D7F60A36074EFF5E6BB6C319D7E595E1A" + + "F676D24709D8C0A2DB9BB5AD2A0FC0342C77F098C2BA51CB4A1E1B3E26CBC64D" + + "6655704BAF173EA6C38740A9DEDCCF378D7C95588F3F767A9BFF8B0B6DFE668F" + + "1475A860F86E782469F21486C001BFF476319C6E5F9FEDFF8BCBFB4F7012A68D" + + "C85EE96590FC71DD8ABB0C967724564082533DADE23522D73D56707E22211A71" + + "EDD5F62041A79500840D808C61644B1746865D84A6021C20A0818DC173B16263" + + "01F462E54115E15726C1C897CEC39466117AE2AB5C15EAAD645F04E59E7F5E4D" + + "360AC5B4CE7F06C197C3FE699CDAF1B27A197897F97D0FD62D5F9F8FD3CD0D66" + + "13D01CD2DE930C147A7CFE4787763DC0BD864185F9DD9D50A231079B92ED32A4" + + "D290B85142FACCFBC2FE1A9823FDB1E4D5AAE57826F39DBEA82E2A8D7BC8D6CD" + + "B9FC1407BE84447ED48EB17FD3529091FB78398D56CB8C797CFB2574ECDD9732" + + "023315A77D3BCE8EA9DC29FA97F23A09BD5C546A524BDB3C7F4870AC7CACE935" + + "F13C1466ADEF7E66A405B28F4A59589149524A429E03854E62297CE26A4DB720" + + "9BFA48AB52F3646FB5421494C287C30EA2E2311EAF42C561CA144A5C7C592004" + + "88C8D85E9A89EB36C94CB18A2AC306ADC55197C21106137CBBA023DEB14561C8" + + "B6C2B789BB542816CE48F98CC68D65B1DFC406E2E99A80816D069EA1BF2117DB" + + "50D4ACA51B19AFF8669347DCAFB227D827137E633AD37727C352E1CFE184EC5F" + + "D567B865C63BDDC66D16BDAAB053EDD9210EE167F28D9E885262DD8B142A0143" + + "1356A942FE56D9B49E343F9459597C02E2EEEC4F59BBAA06BD9D6E9906ACC2AF" + + "85129F72F78FF97D2FCD0B6A6CC6DD6E2A5A92903B5A35C04DE62259A128CD8E" + + "A162057FE51667D2AA4D661AE36728A424D359409678956EFF604CB254E0A1C6" + + "822C1CC349AA77541D101FC5A0D487C33FBBC318E14FB1B13B74F6C41E9C53EA" + + "ABCFF7FBEF0D370E85A5918BC170AD62BFEFB8B46273901FB9615A808B912183" + + "25E79F666DCBF60B2FFEA25680E1AF19EDC0768AB6C1BAA67304F2FD25AED2B4" + + "BBFEB8BD4FABE09AC3B1298B4CAED0772C5B8EDE2063E0A65C424AE2BA344B56" + + "9E8DAA789B5799480E293EFBD625F8C3482F81C25ED9A44B41DE951D3B0565C7" + + "4889C29C101B9921952D2D7776212AF33C6F60C55A3BCA457C2045C6F4B0ADE9" + + "F4B63CE3148F16153C4425373A335EC789BF3EACAB052BA091A75ABDF4E01B7C" + + "F33805702A53A11E5FFD0752E2B6E14CE2840B94FFE53405EE0EE5C43C19D001" + + "7147891D4FC5DE5B949A8C602481D8C1F9F8B2CC3BF2271BB12B306452EC55BE" + + "EE81E13710746EEA3534F106F14DBE9FBD4E00C2FA2A331D2C8FC54607F6A772" + + "D8EE0B3E349448B7AB4E5CC783E72C3A3AC82AAD33F7CBB24403CE167A14798C" + + "E23284BC8A3F90BEBECDC4FB142037CBFD0BE595A6DCB2FEB4B80CDD4136374A" + + "6347898251859BEE1DBF18F3972493474E1DA9B60943D49978A8F4A73470BEB6" + + "E534D3E74726CD08BB6E9A04594FC8AD7F586F52AF8313D41D4DF45826A300CE" + + "2E6225CC0FD912F6D56A46A6BE4DB2CFCFB16CBDAEF928F6ABFCC212B12E3A51" + + "33864B1280EDA8E003F9FDB30A06058B35B31B133D67743C934C9CBF3CBDC06B" + + "959340EBACF1D7A781AC1318635697C2D27C00EDCF067A6CCBCADEEFD2CEF3C6" + + "B4E750318182305B06092A864886F70D010914314E1E4C007B00370039004100" + + "300039004200300036002D0044003100440030002D0034004300460036002D00" + + "41003800460044002D0038004200460031003600430044003200390037003400" + + "32007D302306092A864886F70D010915311604143939D5CBE561A3E16AF98C38" + + "5C4DE21C7745A7DB30303021300906052B0E03021A05000414AABF612B1D42C9" + + "7B2A777B2B544302FDEE1129EF0408B1FF31BA6E2D1A2D020101"; + + internal const string Pkcs12BuilderSaltWithMacNullPassword = + "308214060201033082136506092A864886F70D010701A0821356048213523082" + + "134E3082134A06092A864886F70D010706A082133B3082133702010030821330" + + "06092A864886F70D010701305F06092A864886F70D01050D3052303106092A86" + + "4886F70D01050C30240410978E6F227D033AAB5C51682EFFBA56570202271030" + + "0C06082A864886F70D020B0500301D060960864801650304012A0410905BE763" + + "FCE5DCA6ADF7F8E1261A5237808212C059073968AE0766D615903AA16B242ED1" + + "765D4776FCBCAD0EBB59DB954E9D0365C5183E758854B80D5CCBEFD131264AF3" + + "D864832A2C25B8B93DFEB8EF2D4CD204B2ADA80B2B41C4C58E5B48B55EC65DA0" + + "FB083D61288687A896374B6C851B6251C0E661751F7EDF47478B9041EC7F5B54" + + "DB9FB6FB8F4FA58CB9F8AF80D7E33B4D0F36880E2D348B5A84BBEBA738B3A10C" + + "7CF9026327A1D47E695515D2EF2B73ECB46B42DA27917607E3504D7DFA40A000" + + "CB265E4FD9C9DA026104220E3ED100EBCD434AAE29FF89A883B25111DAE8501F" + + "68AE219BA7725B7EA2600841F879E9D57664940D74C36FB25E29ED104DFDDF2A" + + "3F104B6A89A878A85C50133B68C22C00FD9791170287828EE50CDA25EC656C83" + + "7932D5904090337F092B24853D7F4E27108654C5764F04817D8205F661527326" + + "9E7DA0B4982108A91E5344B54A0FC07056326483B0D6D445601888D84B22C8CC" + + "589338DED377ECC841B08B02FA5ED7A1E8841B5BB2E0C5C3CB750EEB49D1BDFE" + + "D10516924049FDB0FDE9B20768ADF2DA0425AC8B4DE6EF89CD6AE5270513D7D6" + + "B78B97FBFFDFC2CAEFC428DEDAB3D44C9917AE8F688F7E3EED875A5203821E22" + + "DBBD45A12E6B3C296F8B37B7782AAE09CE48837E772BAFB0B6063644FF3B3DBD" + + "861115C3B91C14669E5E92CCA38879F6260D387B6884C368F7246DC74387C404" + + "7086ABA92BE2D3783106C3B6BBDAFB7F9788E1315751E411A5DCCFCBB58B67E8" + + "ED207FB88B5E92302B97256C3CCA280D3670A7DEE71639EEFC0546D651F2F400" + + "A45C8B7643DCD814349CA3099A6CF5384CDAB9A9668FED88C40EC7ABD1E0079A" + + "F4CFAC8799506D5330A5A97B2988073893A98611327B9806D5B7E0B2BB46FB0E" + + "A2304A2F6A21357D0A3282A149E6303B8A06D9ABEB0518EE665D05DFD1207CE2" + + "4AAF471334D61524FEB2BCAF02D09C400E6EF7748BC71DC7F2098E82EB18A367" + + "1061F2BDFDB063D1823791C182B22AC24E7128287C036CBFD5998B2BA25B1601" + + "937EF2403AAF3B582662D50558D12F3BFE0C4A4174EE2856171FAAB8DD94A065" + + "8D5016CD4F6224B06E9E7A179BECA8FA90F9419982CB5799AA024F8CD4C33CB4" + + "2BD2BAD207D8EE12F739028B04D7015DA37DEDE30A2855FA99A5D33F68460E36" + + "C7E28CF4C87A13B2E92EA349D394ABE6A9C0BD0A2E9BFBDF8961DAAD2F5BB547" + + "7E088EEDFE2858E816815594DF0D6DF581E41F8E758089344CBF536FCAAE2859" + + "2E170F4A11455DB0D3D7D2D5B8E2D951603B9FAF3AA1F76F9CEB0A4988D0EE6C" + + "F0A6FC537C74F6F1A66C38790BBDEF0DE139DD931F1DA04806474931CE5F5F3B" + + "6B419D2DE5B390F94BB1EBCEBAD49E56A7333C6803C0B30FE9A354B81112A93A" + + "57CA90CE91E9FB92163E87A223D02C917A85F7AED5B4074750B79ECD116D86F0" + + "0C7E053C1D113B3281423F8A3CA78FE67E3DE3E6CD7D6BDAE0E4A69EE3B3EA76" + + "7EB2A9AB24124AE29B00CFA484B8CF26E6C7228CB95261F96E6EB8A0B0EB153D" + + "B6BF8B5D1352CEC2C7FA6C4F5DB10AE2023F85C6A6225127E769205B047AF02C" + + "3F6F18F1B1A590B26F29F1632E47B8231BD40C9BA6AC7140B5493CF3CE58F85B" + + "0ACD857B8EE850B82522757FC12B142C1C8A9E76F68C38C779593207B146D598" + + "64C676CDAA4FE83A3FE6B2974B89D4D04CE9E1ED3A95A1402C1242422A6782E4" + + "EC846091719BAB4A4BA6DF294B3E35764D3E41F2057061354694AB5432B02470" + + "EF92768C838B8E472B5CD48E4BDCACC08157AE2BAFC50C309C30A9B52E12B221" + + "961F251E84C8A69342D14B23AAE57E5295EEDB55A2B3AEE0494CD59CB9B392DD" + + "A1EC7C72282336385561505B1F772BF592C7A3ED6FCE4CCB8249EF83960B841C" + + "9664ECA0409D1DFDB9D926D331011B3FC906968B364CD0C6D0B8523C24204234" + + "CAB129D1A1CF17FAFF85E16B215052E886EFE988813DF5AEF7A525798023021D" + + "D821D867427BB605D7DBB4A522078EC9E3D6E863CB54EFD79B291058EE264945" + + "6D61B5A93ED32B507F0DDFD60BEB3258BBB8577FAA4763E06F77F135C8C62DE4" + + "CCB766EF06DC5A7AAA3E8AC42008DEBE1F70901FAF8B6937FD18FFA9B9DD856D" + + "2136E0814817DE4CC48B129CA09C5A58D7FFCF8C1978C54DFEE521DF01AD683F" + + "682066B142B86CF8BAF94E42369BFC4A5842D9E68C3CB2DF69AD0595D60D998F" + + "DD26984428BEEFB4EF36376D4EA6940CA9A286A7AC285F00FD2AE8740E7BA3E2" + + "1E85CF48F03231CBF7CBA3836A5ACAB14FDDD15F0F90EA21C593FF6E134721E3" + + "FA2704E4473CDBB58A00F88535D5668F9B30A2C11FF44AAA4715BCF6DBC85676" + + "345435564F43A10C1D8BD14434C06A1A75FEC14F77A9102337443EAD5494F2C7" + + "96D8A940F000C78269BC362A08948324057D448966AE0BF05D980DA1C8C8390E" + + "94C56145A62AA07392006B7D36DB3C0541387E826DA682BBAA5436A5DF631653" + + "78D3A1DA28E2B525DAA104457C02A9E2CCCAD37537396478C0441B426197767B" + + "4A37A45D2B31C76DD2DEBB9940D61065F1488DC371B6388BC59054AFEDD80D07" + + "3BF1DC05F10BCD1A519743258CC9354EC43AE806CE9133EE3CD78E2695E0D7EE" + + "017D16A839C66011536EE17C4FF635739828BB6617DC1C74E57702C4BD91B362" + + "2E1DB8D94AD98682B3A07CE713B0C3392081D028E3E28A66DC949513F4CA5028" + + "6A9169A2CE5B16B541440399BA50A98434D62A0C19FD40CF2D6859DC6673EE85" + + "60B7BADADAB9C61B7A7A0CE3CFD261C572B8D6C3C4FAE1B426E8B6CEBECF6D5F" + + "8FB9DF07DA90D0250606B6924363AB365E081C89898C84881965AB4D897FEA21" + + "EFF53408F637A844618288404F251009BEE40D1FBA009AA5F30489FBE4E51467" + + "9346544A82001365FE1F45C5332225F2CDCF9859CF286A0D3C41BF20E421CDAE" + + "96723EBDDD5C7431CA0CADEB4550857DD2828C054F757AC2D62921A7DD6A8FC3" + + "1EFB1E64440FC33DE646AFAE0050CA5BC2799E24CF0C9493396B0EB011393CC3" + + "B8C07AF714B3EAD4FD85959177DF63E84CEC40A449EDE23C3670492E9CE28AFA" + + "4FE4F5AA916E4EA3CCDC2A381EC5675FEB06B541AE428A913CC9EB2C4ED70B04" + + "CB7B0A03776B313326C7698E6EED937C81653421D500D66B70545671C4D0FF62" + + "01B6E6318B177C4FA29B408CAA3776D57B4C0424F7DD0350FBFB60CE27FE8A41" + + "6FB5F61E43DF1538617B993D4229643B7AF9F2F8DB8F5197FBDACBFC8B228019" + + "2A12AC4053B05CF307DCDEC654A0C795A11BFF7E8386F057FEE687C97A2476D8" + + "BF1A7850D8A97FCCF8DB5BCA0818813A05F68B84D5EE3583F8D57E5C919F2F86" + + "800AA4A6A4DDA2A4C6F7028CD9205B7B3A0105CA5394D9B02D74EAE6EC792534" + + "247201A00C32C1C732F863E6538C810D046025CE81B6E7DE5F721F609A3EDBE0" + + "FF0EB459309BEAEF029907C7F16CDB809937057BE54D1FB1DB18B289765F6863" + + "FD398ECECA0524C20709306BE27CC94B3D2C705F7D676BA7CF00DFCFC170F0C0" + + "2EC263AFE2EFC0E6B1B1E7ADA062B2D6DA2D067833B31BE50120351B3EDF8CBF" + + "7BAAA08AFE2A2C3914A1A1AC537AAF4061507066426270E98E6CFBB877BC2AA4" + + "BD3C60EBB630F9788A960BBECE743AC1AE7FCFF28FDE43F7AB14C8216217353A" + + "E25FCB031C2DF336FB09C22D118FF9751323AC9C82A352447F1E6C7AB1E39547" + + "868A5CF5CB44C8108298620E8524A04310EB5C4463D3A50E25AF1ACA506FC1AC" + + "C642C5D5DE0536EC82C8DB9CB17FC612275AD03BF8FF030DD34C3B0B9BC24929" + + "CABC0249DA09CA034A9280CBC3EF09D4C4EB09924F569728499587A1DDA9B185" + + "7FD8B5CB61BE96047A4A5A28C8B7EE4F9F976E0A3CF25620EE783F6BA53719E3" + + "69C3EBF94BC8B229251C34388B01657F0EA45B5FDF1B0EDC25C3F08463ED559A" + + "392820F79CA86CBC0CA7034BF996E98E4FC0255DEE55EC693BD7E20FA123EEB1" + + "BD5FF110E8D85348036342A3330573C03E9F3949ACEB03AB5010173871BF1DAB" + + "AF12D10596AC8E22C48B45CE0E69C6881A4CD268401993631F47A1BEA6C90DF0" + + "CD26D86D32CAC9307FD864CF44841095F636D38233CA73812E9AB12DFCADF391" + + "D9D8733A6D039399871B479B734DCE9A358F5FAFCB39AB43215F8A0635EBC0A0" + + "943EEBA6E7726E57E2F041467FED30D543785B47476DFC0A1BB36C61C726C4B7" + + "1720428889B9F8CA2A82168469EF7E1EEC52E61B8676FCEBFE49E1DBF13761DA" + + "A66DD693BA7E311B042E3BB978DFC50F7177244F8AA32CC09234B7F83367967D" + + "17856EDF91D1D1357B1B4BAC1191BD692AD06BF215CE76B9530B4993E5613D7A" + + "D7FD354D89FAFF2D397E0AEDC3A21D1DA8965CD2C39CA833D218F1B7BFD02643" + + "885881BF15C24916ED1979DFFAAD9B9B6F4A6F4D03C84588CAE47AC7EE9CB9C8" + + "6DCA2DF1D2F92AF46CD5F20E3F7D262C8996FE0CF224FD8D7F848FC2D03E1BFF" + + "01E23DAC01A2A27575CEACD93DB8B330EC4047B82F303177233BFA8094E8861E" + + "0637C9ED617CEFCF60938B78354E80F7E405474BDC35548553D8AF005DE611BD" + + "B52425A99CA1475C63ED881AC909F9B35C83B8572F4A0B51E4E6A66D0381F1D0" + + "09D71577B22D58314023FC3DAD9E10D95D3E340B77A962B93B13E4F595B4BA82" + + "FEF8CB6A7E3F92FBF811CC41D75AD49FBAC4EEA9066F2DACF868CDA63851E1E8" + + "8C939CA85A70D0375D4C9788AFAF31150DEC9AA7401577239C094A8A6F242103" + + "06FF01F613E50249E7CB850109A8CC7FF8A07B8DDA5EE2FB964779F7EB7FD093" + + "47CB0065F2A6B473B974BAFC40A3733D13FECF8C1F4DCCE5FD1FE8791A3B0979" + + "3B84F5A05A80A8B8A7F37197CF4CE48152D052431636863AF42F3240D5B8D4F8" + + "4BB2027B756B54CE93C0902A2DABE8758D118D5E6DD5F60AA44BEE1150ED7551" + + "4610402F58FFAB5C2E6FA177E7C250D8409F6917A5C37A7C051FF62A74EB03CC" + + "74017451A96CF9356E08C75DE4C86AFBF6D2A170BB09251EA914D65FBE1686E3" + + "82F96A7A21840E7AB172D611704D7E32B0C2F4829C8E7576E9BE3332112868A0" + + "1479B6C114ED7983FB9F30B44F299F58AE2925587BCD66F5B9F3E221CE1DF9DA" + + "749D6397854FE5D972805C693FB18943BAA8FBC55B8CF24747217F803F74B2C5" + + "E7637AC7D576E23F644E3E6CF24113E64E1CCFABC56C4BA104BA69A14A9A69F8" + + "B6B1DA8AFD9C8F6730F5BADD3F63F557E63B7BF98DC3DA725AF8485047F61559" + + "03BAD87ED8CDA9EC21BE96B60326F9465119E3F069FA147A25FC11343D531954" + + "CE81C15B31838B8EE1CD25B11AE4A8A7FFC68DA57A828318BBED76596A550C68" + + "72982E099C070812E20C099EBF882B86AB722F02F0EFEAE73CD885E6C36F02F8" + + "1C8DF15AE3C01F0370B02706B0BF4AB292E1488450CE70EDA02292323979415C" + + "91DD1391FEFD5EF4EA539BBFAF1E361826454A2E6CC32324D6C3A5F5D7D88372" + + "3258E59706A650F19B5A6A1C2EDACD23EE3CCCB1F09B9910DC3256DA7A851B8E" + + "A110319F11CCFE7EAD2DAD4D73312A64D6A15D9EBC5DDC912562FB494194B5C7" + + "72290595529184953D1DB67035CE1DBC6C05E15131E2F4114A6D6A0B54866DD4" + + "DCFC00475FCC5C44B3494D23A703388314E20EAFF4C4A034EEA686D589A7E128" + + "CF12599CE46BF7F6E1415CCEB27E3DCCD6715949DED6C4CAC4479F442D4554D0" + + "D0181F637098C9F72B0751F508394C06682A22BE7D587788D010D24786C5E156" + + "A07785A78F737D924580CEA11B845548711310D9D29B04364965252CBCC68A99" + + "B0E8FF248B8F706CC61EB5F0B1142F17FA96E3DC4F43449419ED9C348EBE07AE" + + "66ED2CF037AB4C7B814C73C9F7E7A0B82BB4CA5D301AEE6D1B82858568EA263D" + + "3E5536614A7C77F3AECDF941424B09792246A9738AAFED3939EC319569ED4875" + + "A1B09FDD2167950BF95DAD59F8DCE0FE450E765D0B703FFEB330D032884071B2" + + "F3DE1FF0F5E43C7F180E3F0B45744802E8113311E58C2776A4484A8643CF2567" + + "2638C63B40DCCF80F767D26A5E4A830E15397787FA550FFB0D07872EDD38BBCB" + + "7555C9D7637A503C26E4DA6BB41052C0E1DA2A7B7F33C74EFCC529EFEE43977B" + + "8373A2210EBDB9A7126AD0A6742D7AAA7A73E9BE546344FB35043209E3C8BFB0" + + "527AB4456E6D9F873B4C238DA0491D930EA654F71910ACD69973F01713817B0C" + + "1165F22BDFDA789DBE3D01A3375DEC8C40A0A6EB977B10929CEF89B61274D332" + + "ABFBDA987CFCF14EA59C3FA5D7138AA8C32E1CCAEC3D229E1B4A46A2A9F02EBE" + + "5EEAA9D88122BF053F142E42E8A0E1268A19B77CD4B2A45F68B74EE644D3CCBE" + + "FA586076CA0F8FEDAAC1CA11058E4B9896ED529F613E246F2A4CE29ACE49F0D8" + + "FF6C04150DD03F526DFB7AE7DD751FA746C378AB0D658BB4A808955C9C8C3B36" + + "79426C1941F15835D5FD179BAB3D658D4A0462F617DDF5FCD23EF2C899A52D46" + + "60144C01A542DCBB5C15A8086B6E97262090127E5DB9FB999E45B869833E9641" + + "A7795DC55B0D7971A0EA423F306475E80561384169333D7D26299100FCD24B3B" + + "5AD6A215B8323CAD902A6C1B97A19863F4DDF460780D188391FEFDF013EB4693" + + "D3CFA097C480A10502F21CF5C1C2C45E9CDA63604008EAE8C11112167F539F16" + + "236A4B50D76E8C143AF38ECB60CE07572E9F31C5517D1CCC20AD644B3361EF25" + + "84ED7840AB11F901556CEA40435FD9B491EAD820DBC283D4BFBA3B00A8CF2F0B" + + "99627225326C9C7DF70C89E112CF06C9B9B968E28A148B61BE10B7C8670925EE" + + "77EBEC504F822614D0B0F3F0CDCA3EA9308197304F300B060960864801650304" + + "02030440699B89444D5AB2D939E849803579B6C1651E206FB208C67F879AFFD6" + + "32E080D8D15BDD48651241FF03180ADE528193DB946145CFAA069790AF3405E7" + + "81BA7445044055FC4F56A8FA8F63539E4AD754A11A1CE1BCF972388D24023EB4" + + "0E8B8907D86A9F4715D3591307E9DFC832B7756EB214BDADAB09F9E1E61AB184" + + "3EC3297C0D4302022710"; + + internal const string Pkcs12Builder3DESCBCWithNullPassword = + "3082088E0201033082084A06092A864886F70D010701A082083B048208373082" + + "08333082082F06092A864886F70D010706A08208203082081C02010030820815" + + "06092A864886F70D0107013024060A2A864886F70D010C010330160410F19120" + + "18896CFBB4653C4B7C06E67C7F02022710808207E02D736F0AE772F48FF976AE" + + "91E8614648678AB5A318CF7D577713881F80B0D6FBF645446359584803814B99" + + "1A8BFF573CBD1D52AC5237EC7A42ED303474221F91529FDE33DDC2126EB4AAD7" + + "65CCAC633209A0AD43DCDB5C1D4ECFEA856EFFF607F03D66B29D433F268C7E74" + + "993F5F2384F9E0D08C6657CC7AD32549CB8D893A1EE37A24E398A44987D23E79" + + "B3E4F3F48B106FD6193812634F999CDEB1E5E3485D642B4DA850BE1C210F9321" + + "3BB1E01AB38465C5B23FB80AAA6E1421A2F20BE775F658BB52F57B4CAB79197D" + + "E65860D656CE8135E235A3C7E06B511F1BE398C03416BC137E063DC8CF8B7100" + + "628DC62B87A70A282C11BA08A08AB0E03814A9B1940145AC0EC3327396AD6984" + + "4BE0B4883DAFC5A611804FB628B598DD006ACC039A86B23100B102E1F4B3CCFF" + + "06FA1E9841DBA8913B9D1D15D6A16330A94F55B04D9779A90EDC91230A664C41" + + "9AC825594D9F3F39A08074E06E5B671469E3AC9D20D906FA9B99CDAB6696A952" + + "49F7B3CCBB8EC1BB2714C248AE0C3D0934F949D68995A785F782910BB8457B66" + + "1B4EADA3724023BE1DE63144C3661055986A2E4D2F59A2DC018EB8E6178E9DAE" + + "14027352738A4D3579C55F48D0C373C9280689DC509EF602C69EF10566043EF9" + + "F1A0852A618103B6C2039574696D64C8492963B54C5BCBD4B124FF5F93B04DF2" + + "F5C1FB577A2BF8D24D29D7C6630071EAB5A3CCBF7DA9B4F7CC39673CDD25ABB8" + + "9A805838B32A002CEEC02404A78BEC048DE5D8AD470FAAF89F31EA7E42ED1DD1" + + "20B66246AAB7BA1FEA3DCAF7A78BCF679A3FAD5029318D69EDA8F081FC7216A3" + + "EB610BA3F6EEFE78660CDB365055110446F73D0FB468D4F4FFF01C394C9FDD20" + + "47792192AD9A46458E3BB63BA4703A7D8D4E56776D48312C5033497795A396B8" + + "60115AA3FCEB1E3CAED4FE9211787A8B4B0BC1671A3104DA4A7925A1E3D661B4" + + "35760FD3DDF71A5902269288512C637C94DD1DB6B8551EE951019294342A50BC" + + "4310BACBEF7313D82CE7D351FC2E9114BA421FF1EC206BFE1DCA5E772E90BB92" + + "E7DEB1CE899CD9328C09BF299F7ADFC9D43AE4721FD36BAA93E50EA6B8B6DA5C" + + "7A188AEC11EAC6EE755D60BA5FE98ED8B8D2360972C114DB4A17CEB5BF8EC1DE" + + "8EA0D6A4B26F40376B2C5D66657DCE4A2A2F3E519C65035E51981A6A74415AFA" + + "9BEDB27B2A6B175DAA953919580EB1ABF52D15E2CCC725AB0BE5F09864FBD0E3" + + "6EB76E8ECCA70C1A850197BA84698A00EE1AE2EB95DD79F002EC2401DF3AE3F8" + + "1C68FAD724C59E51AB60AB22C60A2E6E0CCE2E9BA5F9E2E503946CFA77CF6713" + + "E9B98253C42F3A68A6487D2CA4ADF6D0CC8A13962F5569AAE34C3500414CB363" + + "DDED7F3D3BD5BF6A0E1B229136F23362FD016595AD0F825E30BEEB9E2F95124A" + + "6033D3BF9CE8758AFD964B10437DEFD03FB28BD46D3153FACF19D6405D260B1B" + + "257B138D0BDF3AC006CE3C22D1626BE10E8613F6912536D07EBC6142D3EE8A3B" + + "9D7321D35DB2A78A1C3376894D5C2A1C3E41BD7BD8190007327505E76247C6D7" + + "3B7E78E098F4504B205D35EC50987B601F76FE6363AC0E2FDC89853CEEF2BFC1" + + "08E4CD798C20AA7B326A81736B5FDB9365B5272DDF0CB692230A5C69A37DA5A4" + + "7241213B95C44B9733700A7D4216043860C649E979E9B8C304C1C02E7981A502" + + "60233E8539A01A361FDE3B83A8B42259FCDAD89FA279CEFBA6F769C562E75E9F" + + "58FCE65C6D11A7F701161092E78DDBAD9D3FD407DDF675A46348DF53E9EF7CD5" + + "FB7CE0A3C1B7EA0138529D061CD3CE3A76FB40138ECCD2A29BED34E27E2494D2" + + "D3787326C11AAE5933BAE7FFA6F5F21D33FED6CDDCDF5CEE3C1D7A8FADCD8EB2" + + "E77A75D01A50B38E445D91A986F8D1C1100E37A9AA5E83823280236482425DEC" + + "F49EE6D898E9D8FA3E0F502B50EF968AA14220E926D1ABDD225624E81AB0DACA" + + "A781857C260B9E712F644A87D5AFE0EB3D73C9999073F3C3835473C3C4716990" + + "DD57540B5A0A2D433F3A7F6CA74D046658FF85A9AFCE68DF76ADFC9CB682F80F" + + "29F1A15257A9ABA43641C68A405A88F499ED3B29D097BBA995F1D29616CC47CD" + + "D8FAAC992A8E88D7A4E033E1D37B5DB2F38DB1E37B2A6B1A094A621BBDB70B67" + + "EB35E63425BEE4C0549D2B30FC9207FFE0BA8C3B39EC8562AB61D0A77F78CAD9" + + "D5C6227C7EDD91316D5202D6AC8CB5503F4FA01BB76A47C59FBEAEF8064709A6" + + "CC2DD5BFAF4C96535A1F699AAC58C213BC1DA0043252C5C2E2852F3B0326D428" + + "A3EB3CEB1372D65271F23935DA069CDB2E2446B26BB98EE04516548482EF7D9E" + + "2A855266521BED66156D491E7FA20D723054F55930D0E02A356659B7513CED09" + + "8666D05B6C3EC9281048F57031992620BB3F582F5963AA167BC7F8C8DB07644B" + + "8AE5984CBA7122A67275E024B3790178C8DE7F260D0D2FCB643B990FDC514F5F" + + "88B9EE89D16B20E26FBB2FE315347E972A25B6DE4DED8D69526C506004C46918" + + "13567486B8CD40E4D710069F137ED0E5EC4A493ACA9545F395935E145CB63354" + + "4D436F9FB5BDF0B154E72867FCD9A2F8675D38FAD9CBD2B1A4EC01B78C229445" + + "FD2B4232DA613A5BD9847CC2F19E624F6B1223E82F6F12CD97740E938C34FEE2" + + "54F775437183BD93D52F96C4C1ACE5ECE2D70F1C42DAA699BB76AEEA5693C7C4" + + "0B5DCB4E6D61E648E5335B06B2E0BFB55F2F338033DF38D8A2C8AD9760F0B21E" + + "8DB0DF9AF8E682E6F62F0C70A9E921FA86A7C9EFFFF2A4302F94604D1F991AA4" + + "F6B1D3B7E46BBE4126C874583281746CDEA73337A904110E94B333CB6BFFF28E" + + "1D0A0516EA5F72876614328AD34B4C1148B0930A2E303B301F300706052B0E03" + + "021A0414C1F4E43998F3594C85C97FC9C5777848189A67420414104FBC73DE62" + + "EFB93E15B5A39DE7E0C1B46E20E102022710"; + + internal const string Pkcs12Builder3DESCBCWithEmptyPassword = + "3082088E0201033082084A06092A864886F70D010701A082083B048208373082" + + "08333082082F06092A864886F70D010706A08208203082081C02010030820815" + + "06092A864886F70D0107013024060A2A864886F70D010C01033016041039A75E" + + "DA3FFCB2391E25BF504AC4BBAA02022710808207E0A9EFBDBE9CCF94EBD69A0A" + + "22DAD13EE5036E45C5A28F2C15888DE9A6E357D3A35E9C466E3101DD33B08AE3" + + "B17103506D371A69D230C1F00DE33487E0B9DE8318DB88397D13A6B8B172CB2D" + + "C57CE7D3D273878ACDEEA06F6D49D06757B7CED3F6958D98620AD7FB303D9CE7" + + "5F0B0880C9F3D2762157B946963FCA3E4C7DD3CF1BD359CA27CEDEF45613D8C4" + + "2ADD13B133997B508A53C56C1581A87C03F0A946C33226D6F40F523B7F920985" + + "470B0B5E5EDD5401C4BE78072D3333CEDF47FEBF83EEFBC7E6F9D9D02AE95384" + + "B68DF04EF7BA859B6D5AFC6FD9C918BEF427C49D5097E7645FC3BBFD9CA29EDB" + + "09F89908937E2B51FFA2F806CA0EE6E09A1CDC9F73D3E8393F1B9DE437709FF9" + + "59E4AEB2524C15269A871A4F6201D15846CA40F7F052AF72909878945894016F" + + "6BFF0B966338D371BAEE16EF7E3151FEE91F3EB6AA48E91B7580FC1ADB3456B5" + + "2382EBAB36548CA3521A583647CAEB75C50EBF485AECD50EDF6DF6B630031A5C" + + "FBDB9340C05F5F94B2622B8A0DB23B2D658D6F5733DD65328B1EDB4779D318E7" + + "CC704C7B7B78B950DEFAE77872CAE2BB1E25BA7BCAB8C04ED12F6EAF48808C79" + + "7E9C04FE4F7444A7B58D7E8A6E5445729C44E9118158C62E2760BA6D014EF026" + + "8EFD70AE83E45FC1EF05B9043C55E5AC4393508CAF2A36932ECDF77495C35036" + + "4F4C92AE4DEF9475A7F274F946EAF3347D05BF49725C86CFF72579006636F096" + + "FA49D5183100271F94C19D292DE0A7C78A8D2AA347396ACAFF36A123135FDB45" + + "604E3B829C00DF082B7010B41DBD62416315C2AC384E7D700779C592487F69F3" + + "917B391246A24F8E76258F8D3219A3A6D1313443CF78BEF667FBFDC507191625" + + "1913B729E11E895B1840635882997E5C428DB006A875E561AC0758F80F702E33" + + "DD985319B2D6BDB1EA0D403A761968494BC77CAAF4CE42B6E9124083134989A2" + + "877077CAB2F8EDFC8EC13C255022C3AF77A40A3BB5CE1B76A57DC5648234346C" + + "A072852934F310D3446CBD129858D00A64462E89E3C61D128F1C9590CE9A6284" + + "CF29EC375DB56B79F13CB404AC4320BF491472FB0FB1D530D68C82E2029C7CE1" + + "2AF38F419C163454EFFC7FE6EE590BCC3543E2B48AE9A43358E76C4B2D90AEC8" + + "CFC82BFFCCE4DEAAA23E4944C3034B4C1341FCA68246F328B65341442571FEC6" + + "F3671DA0284FF6789452C081DA021CDD3FDBAA34E82FE0C68B75321488018EBB" + + "FE787787A89058696E4F92E23211085EADF706462391F1F631CD87CAD48D72FF" + + "1EDE98CAE24DA0C776F342FECE74B1EEBCA4B8FCDEF4BC9AB952C04F79D5B235" + + "680782399746091BFC93577B863CCF499D93736CAB5500A4C45DE78FAD5E57D2" + + "E22D1A5F7C85FDEBE52F0431F980E90B44C0250079BCB09D4C2E3CCFB6E9930E" + + "B9EA497E7035FDF826600F795E3CC9EB0CE66DC84131B8EE3D55829DF48F6739" + + "0BD11F92B92D20C86B93FC9F9DDEE2C0D7DFF25275BFD25D7C2FF5BED8B4789E" + + "BC5AE940D802C0A86BC0CBE2958BC93B7D80C3272945032AC9B0FAD174A636CD" + + "68500BAB5A53A399A9630F8B523A1639A7B313F3F0517708EFD57E4E57319955" + + "48887831D86087F6D4B5180559CBC461C29327D5161518DD88E0761BF0CE05A2" + + "7FE504C84F6ACBA1C87A1284ACF18D5EE2B17B63549C35951CCC582BB8975EA7" + + "B49E7C061933B53724D25EE9F8F04F2A36B8B1F293A1A76B822C3BB0546C029B" + + "91F3FE656778236EA95B978DAF9987AD80757696DE2393149A260B5EF0C6437D" + + "DA8A63B8A486E14F42B8D1A69725CDE49E68C867B5F87D9E3CBDB4D64045C0CC" + + "50ED426A5F78CA1216AD394F3A4CD33FF6AC219AF8ED4555079511E49C288E96" + + "1165A20134EC21A5100FA597133B2B81646E245E5C94C26247112982667CE49A" + + "5633663629BC8280A4115100F2A3B4384469D3A0A7DE8D35D2FB984EE0190A0F" + + "C70CE790CF27CD3F4D261F941BEA6478CE155C5A409204F1298FCA20B1D3F095" + + "ADE129236F101BBE9D766DAFFD9D12296AAA618FE1FA8E0EB0B4D873AF67B1DC" + + "A3AC63D935952FF833621D1E7E06AE0C5749E60941D9B29D3E68968DF21E31AF" + + "DAC972B604CE613E98BBFB40BBEADA6AE85F716BD655066B1CCBEB11CB48C5A7" + + "56B4B7C96BE9DCD3DC8B74CAADC4CA7038DA00B867B35185355EB0D2C2FC76D4" + + "2842B307D92B707CB61F9BC8BF6AB1FC9EE8D0F5A8C3A1EECED5D6FB1D13A38F" + + "B2D17E0513AA4F126B5D5FC9029E574179C447D04D5A22063B60E88C48A4F52C" + + "949F49841DBF73A2F884239F18BBE35453BF67611036781876920157358303B2" + + "BF9D17473EBAD888D5A612BDE9AC41778B33F660C7C2922B654CAB899F16F017" + + "ABDE8660ABF43652ED8AB2B9177CB407E79B3B94FDD61407618B77FE980A727B" + + "BBC8B3034B0FF138C6B32B0AC9B0A851FEA1A8383EE1C571A55E0ABBD63B55BC" + + "3A5F87A3ABC9D69BFAC4FE5AFF937F536A66D9EECC8CEB491BFD3505564AA8DB" + + "0EB624817F7D6E848E505C320349697F13026A024F8D5C74E0DE9065974CD0C1" + + "D8D6D7C55C0721EFF5A960C6A44F7FCFC432998859C397C33171A3E539BB2FB3" + + "C0939BFC3D63BA3D03EF18F11CCFD4F95AB2C99AC69CCFAB692659193FF81FB6" + + "5A2A4ED12C75E2B3E12C5B76420FCB34C94CB5140AAE2F96F5CE0C6C2784CF30" + + "88F10B7DE2B2FE8F486E7A5A8858891A98DC460C51730909688BC9E1DB92DD3E" + + "B6BED869FC7D708FEA4BA6FC5DEADAF86DEBECC75A4FB0FB61FD19C05F371EBC" + + "EA880808ABAA83CE2B447F7DE021900D6777A7377FB990B85DDCFE64A36C8FD5" + + "09463C6E50BCA36EB3F8BCB00D8A415D2D0DB5AE08303B301F300706052B0E03" + + "021A0414A57105D833610A6D07EBFBE51E5486CD3F8BCE0D0414DB32290CC077" + + "37E9D9446E37F104FA876C861C0102022710"; } } -- GitLab