Skip to content

Commit

Permalink
Skip RC2 encrypted PKCS12 files on Android for iteration counting
Browse files Browse the repository at this point in the history
  • Loading branch information
vcsjones committed Jul 13, 2023
1 parent 2f853d1 commit dedaf46
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Microsoft.DotNet.XUnitExtensions;
using System.Collections.Generic;
using System.Linq;
using Test.Cryptography;
using Xunit;

namespace System.Security.Cryptography.X509Certificates.Tests
Expand All @@ -20,7 +21,7 @@ private static readonly Dictionary<string, PfxInfo> s_certificatesDictionary

[ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
[MemberData(memberName: nameof(PfxIterationCountTests.GetCertsWith_IterationCountNotExceedingDefaultLimit_AndNullOrEmptyPassword_MemberData), MemberType = typeof(PfxIterationCountTests))]
public void Import_AppContextDataWithValueMinusTwo_ActsAsDefaultLimit_IterationCountNotExceedingDefaultLimit(string name, bool usesPbes2, byte[] blob, long iterationCount)
public void Import_AppContextDataWithValueMinusTwo_ActsAsDefaultLimit_IterationCountNotExceedingDefaultLimit(string name, bool usesPbes2, byte[] blob, long iterationCount, bool usesRC2)
{
_ = iterationCount;
_ = blob;
Expand All @@ -30,6 +31,11 @@ public void Import_AppContextDataWithValueMinusTwo_ActsAsDefaultLimit_IterationC
throw new SkipTestException(name + " uses PBES2, which is not supported on this version.");
}

if (usesRC2 && !PlatformSupport.IsRC2Supported)
{
throw new SkipTestException(name + " uses RC2, which is not supported on this platform.");
}

RemoteExecutor.Invoke((certName) =>
{
AppContext.SetData("System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit", -2);
Expand All @@ -43,7 +49,7 @@ public void Import_AppContextDataWithValueMinusTwo_ActsAsDefaultLimit_IterationC

[ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
[MemberData(memberName: nameof(PfxIterationCountTests.GetCertsWith_IterationCountExceedingDefaultLimit_MemberData), MemberType = typeof(PfxIterationCountTests))]
public void Import_AppContextDataWithValueMinusTwo_ActsAsDefaultLimit_IterationCountLimitExceeded_Throws(string name, string password, bool usesPbes2, byte[] blob, long iterationCount)
public void Import_AppContextDataWithValueMinusTwo_ActsAsDefaultLimit_IterationCountLimitExceeded_Throws(string name, string password, bool usesPbes2, byte[] blob, long iterationCount, bool usesRC2)
{
_ = password;
_ = iterationCount;
Expand All @@ -54,6 +60,11 @@ public void Import_AppContextDataWithValueMinusTwo_ActsAsDefaultLimit_IterationC
throw new SkipTestException(name + " uses PBES2, which is not supported on this version.");
}

if (usesRC2 && !PlatformSupport.IsRC2Supported)
{
throw new SkipTestException(name + " uses RC2, which is not supported on this platform.");
}

RemoteExecutor.Invoke((certName) =>
{
AppContext.SetData("System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit", -2);
Expand All @@ -67,7 +78,7 @@ public void Import_AppContextDataWithValueMinusTwo_ActsAsDefaultLimit_IterationC

[ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
[MemberData(memberName: nameof(PfxIterationCountTests.GetCertsWith_IterationCountNotExceedingDefaultLimit_AndNullOrEmptyPassword_MemberData), MemberType = typeof(PfxIterationCountTests))]
public void Import_AppContextDataWithValueZero_IterationCountNotExceedingDefaultLimit_Throws(string name, bool usesPbes2, byte[] blob, long iterationCount)
public void Import_AppContextDataWithValueZero_IterationCountNotExceedingDefaultLimit_Throws(string name, bool usesPbes2, byte[] blob, long iterationCount, bool usesRC2)
{
_ = iterationCount;
_ = blob;
Expand All @@ -77,6 +88,11 @@ public void Import_AppContextDataWithValueZero_IterationCountNotExceedingDefault
throw new SkipTestException(name + " uses PBES2, which is not supported on this version.");
}

if (usesRC2 && !PlatformSupport.IsRC2Supported)
{
throw new SkipTestException(name + " uses RC2, which is not supported on this platform.");
}

RemoteExecutor.Invoke((certName) =>
{
AppContext.SetData("System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit", 0);
Expand All @@ -90,7 +106,7 @@ public void Import_AppContextDataWithValueZero_IterationCountNotExceedingDefault

[ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
[MemberData(memberName: nameof(PfxIterationCountTests.GetCertsWith_IterationCountExceedingDefaultLimit_MemberData), MemberType = typeof(PfxIterationCountTests))]
public void Import_AppContextDataWithValueMinusOne_IterationCountExceedingDefaultLimit(string name, string password, bool usesPbes2, byte[] blob, long iterationCount)
public void Import_AppContextDataWithValueMinusOne_IterationCountExceedingDefaultLimit(string name, string password, bool usesPbes2, byte[] blob, long iterationCount, bool usesRC2)
{
_ = password;
_ = blob;
Expand All @@ -101,6 +117,11 @@ public void Import_AppContextDataWithValueMinusOne_IterationCountExceedingDefaul
throw new SkipTestException(name + " uses PBES2, which is not supported on this version.");
}

if (usesRC2 && !PlatformSupport.IsRC2Supported)
{
throw new SkipTestException(name + " uses RC2, which is not supported on this platform.");
}

RemoteExecutor.Invoke((certName) =>
{
AppContext.SetData("System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit", -1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,18 @@ public abstract partial class PfxIterationCountTests

[ConditionalTheory]
[MemberData(nameof(GetCertsWith_IterationCountNotExceedingDefaultLimit_AndNullOrEmptyPassword_MemberData))]
public void Import_IterationCounLimitNotExceeded_Succeeds(string name, bool usesPbes2, byte[] blob, long iterationCount)
public void Import_IterationCounLimitNotExceeded_Succeeds(string name, bool usesPbes2, byte[] blob, long iterationCount, bool usesRC2)
{
if (usesPbes2 && !PfxTests.Pkcs12PBES2Supported)
{
throw new SkipTestException(name + " uses PBES2, which is not supported on this version.");
}

if (usesRC2 && !PlatformSupport.IsRC2Supported)
{
throw new SkipTestException(name + " uses RC2, which is not supported on this platform.");
}

if (PfxTests.IsPkcs12IterationCountAllowed(iterationCount, PfxTests.DefaultIterations))
{
X509Certificate cert = Import(blob);
Expand All @@ -40,7 +45,7 @@ public void Import_IterationCounLimitNotExceeded_Succeeds(string name, bool uses

[ConditionalTheory]
[MemberData(nameof(GetCertsWith_IterationCountExceedingDefaultLimit_MemberData))]
public void Import_IterationCountLimitExceeded_Throws(string name, string password, bool usesPbes2, byte[] blob, long iterationCount)
public void Import_IterationCountLimitExceeded_Throws(string name, string password, bool usesPbes2, byte[] blob, long iterationCount, bool usesRC2)
{
_ = password;
_ = iterationCount;
Expand All @@ -50,13 +55,18 @@ public void Import_IterationCountLimitExceeded_Throws(string name, string passwo
throw new SkipTestException(name + " uses PBES2, which is not supported on this version.");
}

if (usesRC2 && !PlatformSupport.IsRC2Supported)
{
throw new SkipTestException(name + " uses RC2, which is not supported on this platform.");
}

CryptographicException ce = Assert.Throws<CryptographicException>(() => Import(blob));
Assert.Contains(FwlinkId, ce.Message);
}

[ConditionalTheory]
[MemberData(nameof(GetCertsWith_IterationCountExceedingDefaultLimit_MemberData))]
public void ImportWithPasswordOrFileName_IterationCountLimitExceeded(string name, string password, bool usesPbes2, byte[] blob, long iterationCount)
public void ImportWithPasswordOrFileName_IterationCountLimitExceeded(string name, string password, bool usesPbes2, byte[] blob, long iterationCount, bool usesRC2)
{
_ = iterationCount;

Expand All @@ -65,6 +75,11 @@ public void ImportWithPasswordOrFileName_IterationCountLimitExceeded(string name
throw new SkipTestException(name + " uses PBES2, which is not supported on this version.");
}

if (usesRC2 && !PlatformSupport.IsRC2Supported)
{
throw new SkipTestException(name + " uses RC2, which is not supported on this platform.");
}

using (TempFileHolder tempFile = new TempFileHolder(blob))
{
string fileName = tempFile.FilePath;
Expand Down Expand Up @@ -100,13 +115,18 @@ internal static void VerifyThrowsCryptoExButDoesNotThrowPfxWithoutPassword(Actio

[ConditionalTheory]
[MemberData(nameof(GetCertsWith_NonNullOrEmptyPassword_MemberData))]
public void Import_NonNullOrEmptyPasswordExpected_Throws(string name, string password, bool usesPbes2, byte[] blob, long iterationCount)
public void Import_NonNullOrEmptyPasswordExpected_Throws(string name, string password, bool usesPbes2, byte[] blob, long iterationCount, bool usesRC2)
{
if (usesPbes2 && !PfxTests.Pkcs12PBES2Supported)
{
throw new SkipTestException(name + " uses PBES2, which is not supported on this version.");
}

if (usesRC2 && !PlatformSupport.IsRC2Supported)
{
throw new SkipTestException(name + " uses RC2, which is not supported on this platform.");
}

CryptographicException ce = Assert.ThrowsAny<CryptographicException>(() => Import(blob));

if (PfxTests.IsPkcs12IterationCountAllowed(iterationCount, PfxTests.DefaultIterations))
Expand All @@ -123,7 +143,7 @@ public void Import_NonNullOrEmptyPasswordExpected_Throws(string name, string pas
}
}

[Fact]
[ConditionalFact(typeof(PlatformSupport), nameof(PlatformSupport.IsRC2Supported))]
public void ExportedPfxWithNullPassword_DecryptReturnsValidPaddingWithEmptyPassword()
{
Assert.NotNull(Import(TestData.MsCertificateExportedToPfx_NullPassword));
Expand Down Expand Up @@ -160,7 +180,7 @@ private static List<PfxInfo> GetCertificates()
certificates.Add(new PfxInfo(
nameof(TestData.Pkcs12WindowsDotnetExportEmptyPassword), "", 6000, false, TestData.Pkcs12WindowsDotnetExportEmptyPassword));
certificates.Add(new PfxInfo(
nameof(TestData.Pkcs12MacosKeychainCreated), null, 4097, false, TestData.Pkcs12MacosKeychainCreated));
nameof(TestData.Pkcs12MacosKeychainCreated), null, 4097, false, TestData.Pkcs12MacosKeychainCreated, usesRC2: true));
certificates.Add(new PfxInfo(
nameof(TestData.Pkcs12BuilderSaltWithMacNullPassword), null, 120000, true, TestData.Pkcs12BuilderSaltWithMacNullPassword));
certificates.Add(new PfxInfo(
Expand All @@ -183,7 +203,7 @@ public static IEnumerable<object[]> GetCertsWith_IterationCountNotExceedingDefau
{
if (p.IterationCount <= DefaultIterationLimit && string.IsNullOrEmpty(p.Password))
{
yield return new object[] { p.Name, p.UsesPbes2, p.Blob, p.IterationCount };
yield return new object[] { p.Name, p.UsesPbes2, p.Blob, p.IterationCount, p.UsesRC2 };
}
}
}
Expand All @@ -194,7 +214,7 @@ public static IEnumerable<object[]> GetCertsWith_IterationCountExceedingDefaultL
{
if (p.IterationCount > DefaultIterationLimit)
{
yield return new object[] { p.Name, p.Password, p.UsesPbes2, p.Blob, p.IterationCount };
yield return new object[] { p.Name, p.Password, p.UsesPbes2, p.Blob, p.IterationCount, p.UsesRC2 };
}
}
}
Expand All @@ -205,7 +225,7 @@ public static IEnumerable<object[]> GetCertsWith_NonNullOrEmptyPassword_MemberDa
{
if (!string.IsNullOrEmpty(p.Password))
{
yield return new object[] { p.Name, p.Password, p.UsesPbes2, p.Blob, p.IterationCount };
yield return new object[] { p.Name, p.Password, p.UsesPbes2, p.Blob, p.IterationCount, p.UsesRC2 };
}
}
}
Expand All @@ -218,14 +238,16 @@ public class PfxInfo
internal long IterationCount { get; set; }
internal bool UsesPbes2 { get; set; }
internal byte[] Blob { get; set; }
internal bool UsesRC2 { get; set; }

internal PfxInfo(string name, string password, long iterationCount, bool usesPbes2, byte[] blob)
internal PfxInfo(string name, string password, long iterationCount, bool usesPbes2, byte[] blob, bool usesRC2 = false)
{
Name = name;
Password = password;
IterationCount = iterationCount;
UsesPbes2 = usesPbes2;
Blob = blob;
UsesRC2 = usesRC2;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@ 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)
public static void TestIterationCounter(string name, bool usesPbes2, byte[] blob, int iterationCount, bool usesRC2)
{
_ = iterationCount;

Expand All @@ -482,6 +482,11 @@ public static void TestIterationCounter(string name, bool usesPbes2, byte[] blob
throw new SkipTestException(name + " uses PBES2, which is not supported on this version.");
}

if (usesRC2 && !PlatformSupport.IsRC2Supported)
{
throw new SkipTestException(name + " uses RC2, which is not supported on this platform.");
}

try
{
long count = (long)target(blob, out int bytesConsumed);
Expand Down

0 comments on commit dedaf46

Please sign in to comment.