Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleanup u8 workarounds #42995

Merged
merged 1 commit into from
Aug 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -249,8 +249,7 @@ public void Protect_InvalidUtf8_Failure()
// Act & assert
var ex = Assert.Throws<CryptographicException>(() =>
{
var plainText = "Hello\ud800";
mockProtector.Object.Protect(plainText);
mockProtector.Object.Protect("Hello\ud800");
});
Assert.IsAssignableFrom<EncoderFallbackException>(ex.InnerException);
}
Expand All @@ -263,8 +262,7 @@ public void Protect_Success()
mockProtector.Setup(p => p.Protect(new byte[] { 0x48, 0x65, 0x6c, 0x6c, 0x6f })).Returns(new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05 });

// Act
var plainText = "Hello";
string retVal = mockProtector.Object.Protect(plainText);
string retVal = mockProtector.Object.Protect("Hello");

// Assert
Assert.Equal("AQIDBAU", retVal);
Expand All @@ -279,8 +277,7 @@ public void Unprotect_InvalidBase64BeforeDecryption_Failure()
// Act & assert
var ex = Assert.Throws<CryptographicException>(() =>
{
var data = "A";
mockProtector.Object.Unprotect(data);
mockProtector.Object.Unprotect("A");
});
}

Expand All @@ -294,8 +291,7 @@ public void Unprotect_InvalidUtf8AfterDecryption_Failure()
// Act & assert
var ex = Assert.Throws<CryptographicException>(() =>
{
var data = "AQIDBAU";
mockProtector.Object.Unprotect(data);
mockProtector.Object.Unprotect("AQIDBAU");
});
Assert.IsAssignableFrom<DecoderFallbackException>(ex.InnerException);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ public void Protect_PayloadAsString_WithExplicitExpiration()
mockDataProtector.Setup(o => o.Protect(plaintextAsBytes, expiration)).Returns(new byte[] { 0x01, 0x02 });

// Act
var plainText = "this is plaintext";
string protectedPayload = mockDataProtector.Object.Protect(plainText, expiration);
string protectedPayload = mockDataProtector.Object.Protect("this is plaintext", expiration);

// Assert
Assert.Equal(SampleEncodedString, protectedPayload);
Expand Down Expand Up @@ -87,8 +86,7 @@ public void Unprotect_PayloadAsString()
mockDataProtector.Setup(o => o.Unprotect(new byte[] { 0x01, 0x02 }, out controlExpiration)).Returns(Encoding.UTF8.GetBytes("this is plaintext"));

// Act
var sampleEncodedString = SampleEncodedString;
string unprotectedPayload = mockDataProtector.Object.Unprotect(sampleEncodedString, out var testExpiration);
string unprotectedPayload = mockDataProtector.Object.Unprotect(SampleEncodedString, out var testExpiration);

// Assert
Assert.Equal("this is plaintext", unprotectedPayload);
Expand Down
29 changes: 11 additions & 18 deletions src/DataProtection/Extensions/test/DataProtectionProviderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ public void System_UsesProvidedDirectory()

// Step 2: instantiate the system and round-trip a payload
var protector = DataProtectionProvider.Create(directory).CreateProtector("purpose");
var plainText = "payload";
Assert.Equal(plainText, protector.Unprotect(protector.Protect(plainText)));
Assert.Equal("payload", protector.Unprotect(protector.Protect("payload")));

// Step 3: validate that there's now a single key in the directory and that it's not protected
var allFiles = directory.GetFiles();
Expand Down Expand Up @@ -68,8 +67,7 @@ public void System_NoKeysDirectoryProvided_UsesDefaultKeysDirectory()
});

var protector = provider.CreateProtector("Protector");
var plainText = "payload";
Assert.Equal(plainText, protector.Unprotect(protector.Protect(plainText)));
Assert.Equal("payload", protector.Unprotect(protector.Protect("payload")));

// Step 2: Validate that there's now a single key in the directory
var newFileName = Assert.Single(Directory.GetFiles(keysPath));
Expand Down Expand Up @@ -103,8 +101,7 @@ public void System_UsesProvidedDirectory_WithConfigurationCallback()
{
configure.ProtectKeysWithDpapi();
}).CreateProtector("purpose");
var plainText = "payload";
Assert.Equal(plainText, protector.Unprotect(protector.Protect(plainText)));
Assert.Equal("payload", protector.Unprotect(protector.Protect("payload")));

// Step 3: validate that there's now a single key in the directory and that it's protected with DPAPI
var allFiles = directory.GetFiles();
Expand Down Expand Up @@ -145,13 +142,12 @@ public void System_UsesProvidedDirectoryAndCertificate()

// Step 2: instantiate the system and round-trip a payload
var protector = DataProtectionProvider.Create(directory, certificate).CreateProtector("purpose");
var plainText = "payload";
var data = protector.Protect(plainText);
var data = protector.Protect("payload");

// add a cert without the private key to ensure the decryption will still fallback to the cert store
var certWithoutKey = new X509Certificate2(Path.Combine(GetTestFilesPath(), "TestCertWithoutPrivateKey.pfx"), "password");
var unprotector = DataProtectionProvider.Create(directory, o => o.UnprotectKeysWithAnyCertificate(certWithoutKey)).CreateProtector("purpose");
Assert.Equal(plainText, unprotector.Unprotect(data));
Assert.Equal("payload", unprotector.Unprotect(data));

// Step 3: validate that there's now a single key in the directory and that it's is protected using the certificate
var allFiles = directory.GetFiles();
Expand Down Expand Up @@ -197,14 +193,13 @@ public void System_UsesProvidedCertificateNotFromStore()
var certWithKey = new X509Certificate2(Path.Combine(GetTestFilesPath(), "TestCert3.pfx"), "password3");

var protector = DataProtectionProvider.Create(directory, certWithKey).CreateProtector("purpose");
var plainText = "payload";
var data = protector.Protect(plainText);
var data = protector.Protect("payload");

var keylessUnprotector = DataProtectionProvider.Create(directory).CreateProtector("purpose");
Assert.Throws<CryptographicException>(() => keylessUnprotector.Unprotect(data));

var unprotector = DataProtectionProvider.Create(directory, o => o.UnprotectKeysWithAnyCertificate(certInStore, certWithKey)).CreateProtector("purpose");
Assert.Equal(plainText, unprotector.Unprotect(data));
Assert.Equal("payload", unprotector.Unprotect(data));
}
finally
{
Expand All @@ -231,9 +226,8 @@ public void System_UsesInMemoryCertificate()

// Step 2: instantiate the system and round-trip a payload
var protector = DataProtectionProvider.Create(directory, certificate).CreateProtector("purpose");
var plainText = "payload";
Assert.Equal(plainText,
protector.Unprotect(protector.Protect(plainText)));
Assert.Equal("payload",
protector.Unprotect(protector.Protect("payload")));

// Step 3: validate that there's now a single key in the directory and that it's is protected using the certificate
var allFiles = directory.GetFiles();
Expand Down Expand Up @@ -280,8 +274,7 @@ public void System_CanUnprotectWithCert()
.Create(directory, certificate)
.CreateProtector("purpose");

var plainText = "payload";
var data = protector.Protect(plainText);
var data = protector.Protect("payload");

// Step 3: validate that there's now a single key in the directory and that it's is protected using the certificate
var allFiles = directory.GetFiles();
Expand All @@ -294,7 +287,7 @@ public void System_CanUnprotectWithCert()
// Step 4: setup a second system and validate it can decrypt keys and unprotect data
var unprotector = DataProtectionProvider.Create(directory,
b => b.UnprotectKeysWithAnyCertificate(certificate));
Assert.Equal(plainText, unprotector.CreateProtector("purpose").Unprotect(data));
Assert.Equal("payload", unprotector.CreateProtector("purpose").Unprotect(data));
});
}

Expand Down
9 changes: 3 additions & 6 deletions src/Shared/CertificateGeneration/CertificateManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -493,8 +493,7 @@ internal static void ExportCertificate(X509Certificate2 certificate, string path
char[] pem;
if (password != null)
{
// TODO: cleanup cast: https://github.com/dotnet/aspnetcore/issues/41455
keyBytes = key.ExportEncryptedPkcs8PrivateKey((ReadOnlySpan<char>)password, new PbeParameters(PbeEncryptionAlgorithm.Aes256Cbc, HashAlgorithmName.SHA256, 100000));
keyBytes = key.ExportEncryptedPkcs8PrivateKey(password, new PbeParameters(PbeEncryptionAlgorithm.Aes256Cbc, HashAlgorithmName.SHA256, 100000));
pem = PemEncoding.Write("ENCRYPTED PRIVATE KEY", keyBytes);
pemEnvelope = Encoding.ASCII.GetBytes(pem);
}
Expand All @@ -503,13 +502,11 @@ internal static void ExportCertificate(X509Certificate2 certificate, string path
// Export the key first to an encrypted PEM to avoid issues with System.Security.Cryptography.Cng indicating that the operation is not supported.
// This is likely by design to avoid exporting the key by mistake.
// To bypass it, we export the certificate to pem temporarily and then we import it and export it as unprotected PEM.
// TODO: cleanup cast: https://github.com/dotnet/aspnetcore/issues/41455
keyBytes = key.ExportEncryptedPkcs8PrivateKey((ReadOnlySpan<char>)"", new PbeParameters(PbeEncryptionAlgorithm.Aes256Cbc, HashAlgorithmName.SHA256, 1));
keyBytes = key.ExportEncryptedPkcs8PrivateKey(string.Empty, new PbeParameters(PbeEncryptionAlgorithm.Aes256Cbc, HashAlgorithmName.SHA256, 1));
pem = PemEncoding.Write("ENCRYPTED PRIVATE KEY", keyBytes);
key.Dispose();
key = RSA.Create();
// TODO: cleanup cast: https://github.com/dotnet/aspnetcore/issues/41455
key.ImportFromEncryptedPem(pem, (ReadOnlySpan<char>)"");
key.ImportFromEncryptedPem(pem, string.Empty);
Array.Clear(keyBytes, 0, keyBytes.Length);
Array.Clear(pem, 0, pem.Length);
keyBytes = key.ExportPkcs8PrivateKey();
Expand Down