1
0
Fork 0
mirror of https://github.com/VSadov/Satori.git synced 2025-06-10 18:11:04 +09:00

Enable importing PEM-formatted keys into AsymmetricAlgorithm values

This commit is contained in:
Kevin Jones 2020-04-09 12:23:17 -04:00 committed by GitHub
parent 755b548206
commit 29df078d1b
Signed by: github
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 2491 additions and 3 deletions

View file

@ -18,6 +18,7 @@
"/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/ECKeyFileTests.cs",
"/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/ECKeyFileTests.LimitedPrivate.cs",
"/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/RSAKeyFileTests.cs",
"/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/RSAKeyPemTests.cs",
"/src/libraries/System.Data.Common/tests/System/Data/Common/DbConnectionStringBuilderTest.cs",
"/src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs",
"/src/libraries/System.DirectoryServices.AccountManagement/src/System/DirectoryServices/AccountManagement/constants.cs",

View file

@ -0,0 +1,170 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System;
using System.Diagnostics;
using System.Security.Cryptography;
namespace Internal.Cryptography
{
internal static class PemKeyImportHelpers
{
public delegate void ImportKeyAction(ReadOnlySpan<byte> source, out int bytesRead);
public delegate ImportKeyAction? FindImportActionFunc(ReadOnlySpan<char> label);
public delegate void ImportEncryptedKeyAction<TPass>(
ReadOnlySpan<TPass> password,
ReadOnlySpan<byte> source,
out int bytesRead);
public static void ImportEncryptedPem<TPass>(
ReadOnlySpan<char> input,
ReadOnlySpan<TPass> password,
ImportEncryptedKeyAction<TPass> importAction)
{
bool foundEncryptedPem = false;
PemFields foundFields = default;
ReadOnlySpan<char> foundSlice = default;
ReadOnlySpan<char> pem = input;
while (PemEncoding.TryFind(pem, out PemFields fields))
{
ReadOnlySpan<char> label = pem[fields.Label];
if (label.SequenceEqual(PemLabels.EncryptedPkcs8PrivateKey))
{
if (foundEncryptedPem)
{
throw new ArgumentException(SR.Argument_PemImport_AmbiguousPem, nameof(input));
}
foundEncryptedPem = true;
foundFields = fields;
foundSlice = pem;
}
Index offset = fields.Location.End;
pem = pem[offset..];
}
if (!foundEncryptedPem)
{
throw new ArgumentException(SR.Argument_PemImport_NoPemFound, nameof(input));
}
ReadOnlySpan<char> base64Contents = foundSlice[foundFields.Base64Data];
int base64size = foundFields.DecodedDataLength;
byte[] decodeBuffer = CryptoPool.Rent(base64size);
int bytesWritten = 0;
try
{
if (!Convert.TryFromBase64Chars(base64Contents, decodeBuffer, out bytesWritten))
{
// Couldn't decode base64. We shouldn't get here since the
// contents are pre-validated.
Debug.Fail("Base64 decoding failed on already validated contents.");
throw new ArgumentException();
}
Debug.Assert(bytesWritten == base64size);
Span<byte> decodedBase64 = decodeBuffer.AsSpan(0, bytesWritten);
// Don't need to check the bytesRead here. We're already operating
// on an input which is already a parsed subset of the input.
importAction(password, decodedBase64, out _);
}
finally
{
CryptoPool.Return(decodeBuffer, clearSize: bytesWritten);
}
}
public static void ImportPem(ReadOnlySpan<char> input, FindImportActionFunc callback)
{
ImportKeyAction? importAction = null;
PemFields foundFields = default;
ReadOnlySpan<char> foundSlice = default;
bool containsEncryptedPem = false;
ReadOnlySpan<char> pem = input;
while (PemEncoding.TryFind(pem, out PemFields fields))
{
ReadOnlySpan<char> label = pem[fields.Label];
ImportKeyAction? action = callback(label);
// Caller knows how to handle this PEM by label.
if (action != null)
{
// There was a previous PEM that could have been handled,
// which means this is ambiguous and contains multiple
// importable keys. Or, this contained an encrypted PEM.
// For purposes of encrypted PKCS8 with another actionable
// PEM, we will throw a duplicate exception.
if (importAction != null || containsEncryptedPem)
{
throw new ArgumentException(SR.Argument_PemImport_AmbiguousPem, nameof(input));
}
importAction = action;
foundFields = fields;
foundSlice = pem;
}
else if (label.SequenceEqual(PemLabels.EncryptedPkcs8PrivateKey))
{
if (importAction != null || containsEncryptedPem)
{
throw new ArgumentException(SR.Argument_PemImport_AmbiguousPem, nameof(input));
}
containsEncryptedPem = true;
}
Index offset = fields.Location.End;
pem = pem[offset..];
}
// The only PEM found that could potentially be used is encrypted PKCS8,
// but we won't try to import it with a null or blank password, so
// throw.
if (containsEncryptedPem)
{
throw new ArgumentException(SR.Argument_PemImport_EncryptedPem, nameof(input));
}
// We went through the PEM and found nothing that could be handled.
if (importAction is null)
{
throw new ArgumentException(SR.Argument_PemImport_NoPemFound, nameof(input));
}
ReadOnlySpan<char> base64Contents = foundSlice[foundFields.Base64Data];
int base64size = foundFields.DecodedDataLength;
byte[] decodeBuffer = CryptoPool.Rent(base64size);
int bytesWritten = 0;
try
{
if (!Convert.TryFromBase64Chars(base64Contents, decodeBuffer, out bytesWritten))
{
// Couldn't decode base64. We shouldn't get here since the
// contents are pre-validated.
Debug.Fail("Base64 decoding failed on already validated contents.");
throw new ArgumentException();
}
Debug.Assert(bytesWritten == base64size);
Span<byte> decodedBase64 = decodeBuffer.AsSpan(0, bytesWritten);
// Don't need to check the bytesRead here. We're already operating
// on an input which is already a parsed subset of the input.
importAction(decodedBase64, out _);
}
finally
{
CryptoPool.Return(decodeBuffer, clearSize: bytesWritten);
}
}
}
}

View file

@ -0,0 +1,16 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace System.Security.Cryptography
{
internal static class PemLabels
{
internal const string Pkcs8PrivateKey = "PRIVATE KEY";
internal const string EncryptedPkcs8PrivateKey = "ENCRYPTED PRIVATE KEY";
internal const string SpkiPublicKey = "PUBLIC KEY";
internal const string RsaPublicKey = "RSA PUBLIC KEY";
internal const string RsaPrivateKey = "RSA PRIVATE KEY";
internal const string EcPrivateKey = "EC PRIVATE KEY";
}
}

View file

@ -0,0 +1,379 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Text;
using Test.Cryptography;
using Xunit;
namespace System.Security.Cryptography.Dsa.Tests
{
public static class DSAKeyPemTests
{
private const string AmbiguousExceptionMarker = "multiple keys";
private const string EncryptedExceptionMarker = "encrypted key";
private const string NoPemExceptionMarker = "No supported key";
[Fact]
public static void ImportFromPem_NoPem()
{
using (DSA dsa = DSAFactory.Create())
{
string pem = "pem? what pem? there is no pem here.";
ArgumentException ae = AssertExtensions.Throws<ArgumentException>("input", () => dsa.ImportFromPem(pem));
Assert.Contains(NoPemExceptionMarker, ae.Message);
}
}
[Fact]
public static void ImportFromPem_Pkcs8UnEncrypted_Simple()
{
using (DSA dsa = DSAFactory.Create())
{
string pem = @"
-----BEGIN PRIVATE KEY-----
MIHGAgEAMIGoBgcqhkjOOAQBMIGcAkEA1qi38cr3ppZNB2Y/xpHSL2q81Vw3rvWN
IHRnQNgv4U4UY2NifZGSUULc3uOEvgoeBO1b9fRxSG9NmG1CoufflQIVAPq19iXV
1eFkMKHvYw6+M4l8wiT5AkAIRMSQ5S71jgWQLGNtZNHV6yxggqDU87/RzgeOh7Q6
fve77OGaTv4qbZwinTYAg86p9yHzmwW6+XBS3vxnpYorBBYCFC49eoTIW2Z4Xh9v
55aYKyKwy5i8
-----END PRIVATE KEY-----";
dsa.ImportFromPem(pem);
DSAParameters dsaParameters = dsa.ExportParameters(true);
DSAImportExport.AssertKeyEquals(DSATestData.Dsa512Parameters, dsaParameters);
}
}
[Fact]
public static void ImportFromPem_Pkcs8UnEncrypted_IgnoresUnrelatedAlgorithm()
{
using (DSA dsa = DSAFactory.Create())
{
string pem = @"
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIHChLC2xaEXtVv9oz8IaRys/BNfWhRv2NJ8tfVs0UrOKoAoGCCqGSM49
AwEHoUQDQgAEgQHs5HRkpurXDPaabivT2IaRoyYtIsuk92Ner/JmgKjYoSumHVmS
NfZ9nLTVjxeD08pD548KWrqmJAeZNsDDqQ==
-----END EC PRIVATE KEY-----
-----BEGIN PRIVATE KEY-----
MIHGAgEAMIGoBgcqhkjOOAQBMIGcAkEA1qi38cr3ppZNB2Y/xpHSL2q81Vw3rvWN
IHRnQNgv4U4UY2NifZGSUULc3uOEvgoeBO1b9fRxSG9NmG1CoufflQIVAPq19iXV
1eFkMKHvYw6+M4l8wiT5AkAIRMSQ5S71jgWQLGNtZNHV6yxggqDU87/RzgeOh7Q6
fve77OGaTv4qbZwinTYAg86p9yHzmwW6+XBS3vxnpYorBBYCFC49eoTIW2Z4Xh9v
55aYKyKwy5i8
-----END PRIVATE KEY-----";
dsa.ImportFromPem(pem);
DSAParameters dsaParameters = dsa.ExportParameters(true);
DSAImportExport.AssertKeyEquals(DSATestData.Dsa512Parameters, dsaParameters);
}
}
[Fact]
public static void ImportFromPem_Pkcs8_UnrelatedPrecedingPem()
{
using (DSA dsa = DSAFactory.Create())
{
string pem = @"
-----BEGIN CERTIFICATE-----
MII=
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
MIHGAgEAMIGoBgcqhkjOOAQBMIGcAkEA1qi38cr3ppZNB2Y/xpHSL2q81Vw3rvWN
IHRnQNgv4U4UY2NifZGSUULc3uOEvgoeBO1b9fRxSG9NmG1CoufflQIVAPq19iXV
1eFkMKHvYw6+M4l8wiT5AkAIRMSQ5S71jgWQLGNtZNHV6yxggqDU87/RzgeOh7Q6
fve77OGaTv4qbZwinTYAg86p9yHzmwW6+XBS3vxnpYorBBYCFC49eoTIW2Z4Xh9v
55aYKyKwy5i8
-----END PRIVATE KEY-----";
dsa.ImportFromPem(pem);
DSAParameters dsaParameters = dsa.ExportParameters(true);
DSAImportExport.AssertKeyEquals(DSATestData.Dsa512Parameters, dsaParameters);
}
}
[Fact]
public static void ImportFromPem_Pkcs8_PrecedingMalformedPem()
{
using (DSA dsa = DSAFactory.Create())
{
string pem = @"
-----BEGIN CERTIFICATE-----
$$$ BAD PEM
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
MIHGAgEAMIGoBgcqhkjOOAQBMIGcAkEA1qi38cr3ppZNB2Y/xpHSL2q81Vw3rvWN
IHRnQNgv4U4UY2NifZGSUULc3uOEvgoeBO1b9fRxSG9NmG1CoufflQIVAPq19iXV
1eFkMKHvYw6+M4l8wiT5AkAIRMSQ5S71jgWQLGNtZNHV6yxggqDU87/RzgeOh7Q6
fve77OGaTv4qbZwinTYAg86p9yHzmwW6+XBS3vxnpYorBBYCFC49eoTIW2Z4Xh9v
55aYKyKwy5i8
-----END PRIVATE KEY-----";
dsa.ImportFromPem(pem);
DSAParameters dsaParameters = dsa.ExportParameters(true);
DSAImportExport.AssertKeyEquals(DSATestData.Dsa512Parameters, dsaParameters);
}
}
[Fact]
public static void ImportFromPem_SubjectPublicKeyInfo_Simple()
{
using (DSA dsa = DSAFactory.Create())
{
string pem = @"
-----BEGIN PUBLIC KEY-----
MIHxMIGoBgcqhkjOOAQBMIGcAkEA1qi38cr3ppZNB2Y/xpHSL2q81Vw3rvWNIHRn
QNgv4U4UY2NifZGSUULc3uOEvgoeBO1b9fRxSG9NmG1CoufflQIVAPq19iXV1eFk
MKHvYw6+M4l8wiT5AkAIRMSQ5S71jgWQLGNtZNHV6yxggqDU87/RzgeOh7Q6fve7
7OGaTv4qbZwinTYAg86p9yHzmwW6+XBS3vxnpYorA0QAAkEAwwDg5n2HfmztOf7q
qsHywr1WjmoyRnIn4Stq5FqNlHhUGkgKyAA4qshjgn1uOYQGGiWQXBi9JJmoOWY8
PKRWBQ==
-----END PUBLIC KEY-----";
dsa.ImportFromPem(pem);
DSAParameters dsaParameters = dsa.ExportParameters(false);
DSAImportExport.AssertKeyEquals(DSATestData.Dsa512Parameters.ToPublic(), dsaParameters);
}
}
[Fact]
public static void ImportFromPem_Pkcs8_AmbiguousKey_Pkcs8()
{
using (DSA dsa = DSAFactory.Create())
{
string pem = @"
-----BEGIN PRIVATE KEY-----
MIHGAgEAMIGoBgcqhkjOOAQBMIGcAkEA1qi38cr3ppZNB2Y/xpHSL2q81Vw3rvWN
IHRnQNgv4U4UY2NifZGSUULc3uOEvgoeBO1b9fRxSG9NmG1CoufflQIVAPq19iXV
1eFkMKHvYw6+M4l8wiT5AkAIRMSQ5S71jgWQLGNtZNHV6yxggqDU87/RzgeOh7Q6
fve77OGaTv4qbZwinTYAg86p9yHzmwW6+XBS3vxnpYorBBYCFC49eoTIW2Z4Xh9v
55aYKyKwy5i8
-----END PRIVATE KEY-----
-----BEGIN PRIVATE KEY-----
MIHGAgEAMIGoBgcqhkjOOAQBMIGcAkEA1qi38cr3ppZNB2Y/xpHSL2q81Vw3rvWN
IHRnQNgv4U4UY2NifZGSUULc3uOEvgoeBO1b9fRxSG9NmG1CoufflQIVAPq19iXV
1eFkMKHvYw6+M4l8wiT5AkAIRMSQ5S71jgWQLGNtZNHV6yxggqDU87/RzgeOh7Q6
fve77OGaTv4qbZwinTYAg86p9yHzmwW6+XBS3vxnpYorBBYCFC49eoTIW2Z4Xh9v
55aYKyKwy5i8
-----END PRIVATE KEY-----";
ArgumentException ae = AssertExtensions.Throws<ArgumentException>("input", () => dsa.ImportFromPem(pem));
Assert.Contains(AmbiguousExceptionMarker, ae.Message);
}
}
[Fact]
public static void ImportFromPem_Pkcs8_AmbiguousKey_Spki()
{
using (DSA dsa = DSAFactory.Create())
{
string pem = @"
-----BEGIN PUBLIC KEY-----
MIHxMIGoBgcqhkjOOAQBMIGcAkEA1qi38cr3ppZNB2Y/xpHSL2q81Vw3rvWNIHRn
QNgv4U4UY2NifZGSUULc3uOEvgoeBO1b9fRxSG9NmG1CoufflQIVAPq19iXV1eFk
MKHvYw6+M4l8wiT5AkAIRMSQ5S71jgWQLGNtZNHV6yxggqDU87/RzgeOh7Q6fve7
7OGaTv4qbZwinTYAg86p9yHzmwW6+XBS3vxnpYorA0QAAkEAwwDg5n2HfmztOf7q
qsHywr1WjmoyRnIn4Stq5FqNlHhUGkgKyAA4qshjgn1uOYQGGiWQXBi9JJmoOWY8
PKRWBQ==
-----END PUBLIC KEY-----
-----BEGIN PRIVATE KEY-----
MIHGAgEAMIGoBgcqhkjOOAQBMIGcAkEA1qi38cr3ppZNB2Y/xpHSL2q81Vw3rvWN
IHRnQNgv4U4UY2NifZGSUULc3uOEvgoeBO1b9fRxSG9NmG1CoufflQIVAPq19iXV
1eFkMKHvYw6+M4l8wiT5AkAIRMSQ5S71jgWQLGNtZNHV6yxggqDU87/RzgeOh7Q6
fve77OGaTv4qbZwinTYAg86p9yHzmwW6+XBS3vxnpYorBBYCFC49eoTIW2Z4Xh9v
55aYKyKwy5i8
-----END PRIVATE KEY-----";
ArgumentException ae = AssertExtensions.Throws<ArgumentException>("input", () => dsa.ImportFromPem(pem));
Assert.Contains(AmbiguousExceptionMarker, ae.Message);
}
}
[Fact]
public static void ImportFromPem_Pkcs8_AmbiguousKey_EncryptedPkcs8()
{
using (DSA dsa = DSAFactory.Create())
{
string pem = @"
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIBIDBLBgkqhkiG9w0BBQ0wPjApBgkqhkiG9w0BBQwwHAQIkM/kCKe6rYsCAggA
MAwGCCqGSIb3DQIJBQAwEQYFKw4DAgcECBOccveL65bDBIHQiCcCqwxJs93g1+16
7Gx1D5lL4/nZ94fRa+Hl4nGEX4gmjuxH6pOHKyywwflAyXNTfVhOCP9zBedwENx9
MGHbpaaShD6iJfoGMRX0frr0mMCtuOOZkkjBF9pSpkhaH0TDSq1PrVLxcM0/S4Vs
+//2uPrP8U+CTW9W7CXCZw698BAuevZRuD0koT2Bn9ErhTiuVZZMcOjtLmN2oXHG
dVYwfovccu8ktEAwk5XAOo0r+5CCw2lDDw/hbDeO87BToC5Cc5nu3F5LxAUj8Flc
v8pi3w==
-----END ENCRYPTED PRIVATE KEY-----
-----BEGIN PRIVATE KEY-----
MIHGAgEAMIGoBgcqhkjOOAQBMIGcAkEA1qi38cr3ppZNB2Y/xpHSL2q81Vw3rvWN
IHRnQNgv4U4UY2NifZGSUULc3uOEvgoeBO1b9fRxSG9NmG1CoufflQIVAPq19iXV
1eFkMKHvYw6+M4l8wiT5AkAIRMSQ5S71jgWQLGNtZNHV6yxggqDU87/RzgeOh7Q6
fve77OGaTv4qbZwinTYAg86p9yHzmwW6+XBS3vxnpYorBBYCFC49eoTIW2Z4Xh9v
55aYKyKwy5i8
-----END PRIVATE KEY-----";
ArgumentException ae = AssertExtensions.Throws<ArgumentException>("input", () => dsa.ImportFromPem(pem));
Assert.Contains(AmbiguousExceptionMarker, ae.Message);
}
}
[Fact]
public static void ImportFromPem_EncryptedPrivateKeyFails()
{
using (DSA dsa = DSAFactory.Create())
{
string pem = @"
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIBIDBLBgkqhkiG9w0BBQ0wPjApBgkqhkiG9w0BBQwwHAQIkM/kCKe6rYsCAggA
MAwGCCqGSIb3DQIJBQAwEQYFKw4DAgcECBOccveL65bDBIHQiCcCqwxJs93g1+16
7Gx1D5lL4/nZ94fRa+Hl4nGEX4gmjuxH6pOHKyywwflAyXNTfVhOCP9zBedwENx9
MGHbpaaShD6iJfoGMRX0frr0mMCtuOOZkkjBF9pSpkhaH0TDSq1PrVLxcM0/S4Vs
+//2uPrP8U+CTW9W7CXCZw698BAuevZRuD0koT2Bn9ErhTiuVZZMcOjtLmN2oXHG
dVYwfovccu8ktEAwk5XAOo0r+5CCw2lDDw/hbDeO87BToC5Cc5nu3F5LxAUj8Flc
v8pi3w==
-----END ENCRYPTED PRIVATE KEY-----";
ArgumentException ae = AssertExtensions.Throws<ArgumentException>("input", () => dsa.ImportFromPem(pem));
Assert.Contains(EncryptedExceptionMarker, ae.Message);
}
}
[Fact]
public static void ImportFromPem_SpkiAlgorithmMismatch_Throws()
{
using (DSA dsa = DSAFactory.Create())
{
string pem = @"
The below key is for an RSA SPKI
-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALc/WfXui9VeJLf/AprRaoVDyW0lPlQx
m5NTLEHDwUd7idstLzPXuah0WEjgao5oO1BEUR4byjYlJ+F89Cs4BhUCAwEAAQ==
-----END PUBLIC KEY-----";
Assert.Throws<CryptographicException>(() => dsa.ImportFromPem(pem));
}
}
[Fact]
public static void ImportFromEncryptedPem_Pkcs8_Encrypted_Char_Simple()
{
using (DSA dsa = DSAFactory.Create())
{
string pem = @"
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIBIDBLBgkqhkiG9w0BBQ0wPjApBgkqhkiG9w0BBQwwHAQIkM/kCKe6rYsCAggA
MAwGCCqGSIb3DQIJBQAwEQYFKw4DAgcECBOccveL65bDBIHQiCcCqwxJs93g1+16
7Gx1D5lL4/nZ94fRa+Hl4nGEX4gmjuxH6pOHKyywwflAyXNTfVhOCP9zBedwENx9
MGHbpaaShD6iJfoGMRX0frr0mMCtuOOZkkjBF9pSpkhaH0TDSq1PrVLxcM0/S4Vs
+//2uPrP8U+CTW9W7CXCZw698BAuevZRuD0koT2Bn9ErhTiuVZZMcOjtLmN2oXHG
dVYwfovccu8ktEAwk5XAOo0r+5CCw2lDDw/hbDeO87BToC5Cc5nu3F5LxAUj8Flc
v8pi3w==
-----END ENCRYPTED PRIVATE KEY-----";
dsa.ImportFromEncryptedPem(pem, "test");
DSAParameters dsaParameters = dsa.ExportParameters(true);
DSAImportExport.AssertKeyEquals(DSATestData.Dsa512Parameters, dsaParameters);
}
}
[Fact]
public static void ImportFromEncryptedPem_Pkcs8_Encrypted_Byte_Simple()
{
using (DSA dsa = DSAFactory.Create())
{
string pem = @"
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIBLDBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIfcoipdEY/C4CAggA
MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAECBBC9heEphj00fB89aP6chSOjBIHQ
HF2RLrIw6654q2hjUdCG4PhhYNXlck0zD0mOuaVQHmnKIKArk/1DSpgSrYnKw6aE
2eujwNdySLLEwUj5l+X/IXwhOnPIZDJqUN7oMagUYJX28gnQmXyDvrt3r16utbpd
ho0YNYGUDSgOs6RxBpw1rJUCnAlHNU09peCjEP+aZSrhsxlejN/GpVS4e0JTmMeo
xTL6VO9mx52x6h5WDAQAisMVeMkBoxQUWLANXiw1zSfVbsmB7mDknsRcvD3tcgMs
7YLD7LQMiPAIjDlOP8XP/w==
-----END ENCRYPTED PRIVATE KEY-----";
byte[] passwordBytes = Encoding.UTF8.GetBytes("test");
dsa.ImportFromEncryptedPem(pem, passwordBytes);
DSAParameters dsaParameters = dsa.ExportParameters(true);
DSAImportExport.AssertKeyEquals(DSATestData.Dsa512Parameters, dsaParameters);
}
}
[Fact]
public static void ImportFromEncryptedPem_Pkcs8_Encrypted_AmbiguousPem()
{
using (DSA dsa = DSAFactory.Create())
{
string pem = @"
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIBLDBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIfcoipdEY/C4CAggA
MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAECBBC9heEphj00fB89aP6chSOjBIHQ
HF2RLrIw6654q2hjUdCG4PhhYNXlck0zD0mOuaVQHmnKIKArk/1DSpgSrYnKw6aE
2eujwNdySLLEwUj5l+X/IXwhOnPIZDJqUN7oMagUYJX28gnQmXyDvrt3r16utbpd
ho0YNYGUDSgOs6RxBpw1rJUCnAlHNU09peCjEP+aZSrhsxlejN/GpVS4e0JTmMeo
xTL6VO9mx52x6h5WDAQAisMVeMkBoxQUWLANXiw1zSfVbsmB7mDknsRcvD3tcgMs
7YLD7LQMiPAIjDlOP8XP/w==
-----END ENCRYPTED PRIVATE KEY-----
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIBIDBLBgkqhkiG9w0BBQ0wPjApBgkqhkiG9w0BBQwwHAQIkM/kCKe6rYsCAggA
MAwGCCqGSIb3DQIJBQAwEQYFKw4DAgcECBOccveL65bDBIHQiCcCqwxJs93g1+16
7Gx1D5lL4/nZ94fRa+Hl4nGEX4gmjuxH6pOHKyywwflAyXNTfVhOCP9zBedwENx9
MGHbpaaShD6iJfoGMRX0frr0mMCtuOOZkkjBF9pSpkhaH0TDSq1PrVLxcM0/S4Vs
+//2uPrP8U+CTW9W7CXCZw698BAuevZRuD0koT2Bn9ErhTiuVZZMcOjtLmN2oXHG
dVYwfovccu8ktEAwk5XAOo0r+5CCw2lDDw/hbDeO87BToC5Cc5nu3F5LxAUj8Flc
v8pi3w==
-----END ENCRYPTED PRIVATE KEY-----";
byte[] passwordBytes = Encoding.UTF8.GetBytes("test");
ArgumentException ae = AssertExtensions.Throws<ArgumentException>("input", () =>
dsa.ImportFromEncryptedPem(pem, passwordBytes));
Assert.Contains(AmbiguousExceptionMarker, ae.Message);
}
}
[Fact]
public static void ImportFromEncryptedPem_Pkcs8_Byte_NoPem()
{
using (DSA dsa = DSAFactory.Create())
{
string pem = "";
byte[] passwordBytes = Encoding.UTF8.GetBytes("test");
ArgumentException ae = AssertExtensions.Throws<ArgumentException>("input", () =>
dsa.ImportFromEncryptedPem(pem, passwordBytes));
Assert.Contains(NoPemExceptionMarker, ae.Message);
}
}
[Fact]
public static void ImportFromEncryptedPem_Pkcs8_Char_NoPem()
{
using (DSA dsa = DSAFactory.Create())
{
string pem = "";
ArgumentException ae = AssertExtensions.Throws<ArgumentException>("input", () =>
dsa.ImportFromEncryptedPem(pem, ""));
Assert.Contains(NoPemExceptionMarker, ae.Message);
}
}
[Fact]
public static void ImportFromEncryptedPem_Pkcs8_NoEncryptedPem()
{
using (DSA dsa = DSAFactory.Create())
{
string pem = @"
-----BEGIN PRIVATE KEY-----
MIHGAgEAMIGoBgcqhkjOOAQBMIGcAkEA1qi38cr3ppZNB2Y/xpHSL2q81Vw3rvWN
IHRnQNgv4U4UY2NifZGSUULc3uOEvgoeBO1b9fRxSG9NmG1CoufflQIVAPq19iXV
1eFkMKHvYw6+M4l8wiT5AkAIRMSQ5S71jgWQLGNtZNHV6yxggqDU87/RzgeOh7Q6
fve77OGaTv4qbZwinTYAg86p9yHzmwW6+XBS3vxnpYorBBYCFC49eoTIW2Z4Xh9v
55aYKyKwy5i8
-----END PRIVATE KEY-----";
ArgumentException ae = AssertExtensions.Throws<ArgumentException>("input", () =>
dsa.ImportFromEncryptedPem(pem, ""));
Assert.Contains(NoPemExceptionMarker, ae.Message);
}
}
private static DSAParameters ToPublic(this DSAParameters dsaParams)
{
dsaParams.X = null;
return dsaParams;
}
}
}

View file

@ -0,0 +1,438 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Text;
using Test.Cryptography;
using Xunit;
namespace System.Security.Cryptography.Tests
{
public abstract class ECKeyPemTests<TAlg> where TAlg : AsymmetricAlgorithm
{
private const string AmbiguousExceptionMarker = "multiple keys";
private const string EncryptedExceptionMarker = "encrypted key";
private const string NoPemExceptionMarker = "No supported key";
protected abstract TAlg CreateKey();
protected abstract ECParameters ExportParameters(TAlg key, bool includePrivateParameters);
[Fact]
public void ImportFromPem_NoPem()
{
using (TAlg key = CreateKey())
{
ArgumentException ae = AssertExtensions.Throws<ArgumentException>("input", () => key.ImportFromPem(""));
Assert.Contains(NoPemExceptionMarker, ae.Message);
}
}
[Fact]
public void ImportFromPem_ECPrivateKey_Simple()
{
using (TAlg key = CreateKey())
{
key.ImportFromPem(@"
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIHChLC2xaEXtVv9oz8IaRys/BNfWhRv2NJ8tfVs0UrOKoAoGCCqGSM49
AwEHoUQDQgAEgQHs5HRkpurXDPaabivT2IaRoyYtIsuk92Ner/JmgKjYoSumHVmS
NfZ9nLTVjxeD08pD548KWrqmJAeZNsDDqQ==
-----END EC PRIVATE KEY-----");
ECParameters ecParameters = ExportParameters(key, true);
ECParameters expected = EccTestData.GetNistP256ReferenceKey();
EccTestBase.AssertEqual(expected, ecParameters);
}
}
[Fact]
public void ImportFromPem_ECPrivateKey_IgnoresUnrelatedAlgorithm()
{
using (TAlg key = CreateKey())
{
key.ImportFromPem(@"
-----BEGIN RSA PRIVATE KEY-----
MIIBOwIBAAJBALc/WfXui9VeJLf/AprRaoVDyW0lPlQxm5NTLEHDwUd7idstLzPX
uah0WEjgao5oO1BEUR4byjYlJ+F89Cs4BhUCAwEAAQJBAK/m8jYvnK9exaSR+DAh
Ij12ip5pB+HOFOdhCbS/coNoIowa6WJGrd3Np1m9BBhouWloF8UB6Iu8/e/wAg+F
9ykCIQDzcnsehnYgVZTTxzoCJ01PGpgESilRyFzNEsb8V60ZewIhAMCyOujqUqn7
Q079SlHzXuvocqIdt4IM1EmIlrlU9GGvAh8Ijv3FFPUSLfANgfOIH9mX7ldpzzGk
rmaUzxQvyuVLAiEArCTM8dSbopUADWnD4jArhU50UhWAIaM6ZrKqC8k0RKsCIQDC
yZWUxoxAdjfrBGsx+U6BHM0Myqqe7fY7hjWzj4aBCw==
-----END RSA PRIVATE KEY-----
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIHChLC2xaEXtVv9oz8IaRys/BNfWhRv2NJ8tfVs0UrOKoAoGCCqGSM49
AwEHoUQDQgAEgQHs5HRkpurXDPaabivT2IaRoyYtIsuk92Ner/JmgKjYoSumHVmS
NfZ9nLTVjxeD08pD548KWrqmJAeZNsDDqQ==
-----END EC PRIVATE KEY-----");
ECParameters ecParameters = ExportParameters(key, true);
ECParameters expected = EccTestData.GetNistP256ReferenceKey();
EccTestBase.AssertEqual(expected, ecParameters);
}
}
[Fact]
public void ImportFromPem_Pkcs8_Simple()
{
using (TAlg key = CreateKey())
{
key.ImportFromPem(@"
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgcKEsLbFoRe1W/2jP
whpHKz8E19aFG/Y0ny19WzRSs4qhRANCAASBAezkdGSm6tcM9ppuK9PYhpGjJi0i
y6T3Y16v8maAqNihK6YdWZI19n2ctNWPF4PTykPnjwpauqYkB5k2wMOp
-----END PRIVATE KEY-----");
ECParameters ecParameters = ExportParameters(key, true);
ECParameters expected = EccTestData.GetNistP256ReferenceKey();
EccTestBase.AssertEqual(expected, ecParameters);
}
}
[Fact]
public void ImportFromPem_Pkcs8_IgnoresUnrelatedAlgorithm()
{
using (TAlg key = CreateKey())
{
key.ImportFromPem(@"
-----BEGIN RSA PRIVATE KEY-----
MIIBOwIBAAJBALc/WfXui9VeJLf/AprRaoVDyW0lPlQxm5NTLEHDwUd7idstLzPX
uah0WEjgao5oO1BEUR4byjYlJ+F89Cs4BhUCAwEAAQJBAK/m8jYvnK9exaSR+DAh
Ij12ip5pB+HOFOdhCbS/coNoIowa6WJGrd3Np1m9BBhouWloF8UB6Iu8/e/wAg+F
9ykCIQDzcnsehnYgVZTTxzoCJ01PGpgESilRyFzNEsb8V60ZewIhAMCyOujqUqn7
Q079SlHzXuvocqIdt4IM1EmIlrlU9GGvAh8Ijv3FFPUSLfANgfOIH9mX7ldpzzGk
rmaUzxQvyuVLAiEArCTM8dSbopUADWnD4jArhU50UhWAIaM6ZrKqC8k0RKsCIQDC
yZWUxoxAdjfrBGsx+U6BHM0Myqqe7fY7hjWzj4aBCw==
-----END RSA PRIVATE KEY-----
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgcKEsLbFoRe1W/2jP
whpHKz8E19aFG/Y0ny19WzRSs4qhRANCAASBAezkdGSm6tcM9ppuK9PYhpGjJi0i
y6T3Y16v8maAqNihK6YdWZI19n2ctNWPF4PTykPnjwpauqYkB5k2wMOp
-----END PRIVATE KEY-----");
ECParameters ecParameters = ExportParameters(key, true);
ECParameters expected = EccTestData.GetNistP256ReferenceKey();
EccTestBase.AssertEqual(expected, ecParameters);
}
}
[Fact]
public void ImportFromPem_Spki_Simple()
{
using (TAlg key = CreateKey())
{
key.ImportFromPem(@"
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEgQHs5HRkpurXDPaabivT2IaRoyYt
Isuk92Ner/JmgKjYoSumHVmSNfZ9nLTVjxeD08pD548KWrqmJAeZNsDDqQ==
-----END PUBLIC KEY-----");
ECParameters ecParameters = ExportParameters(key, false);
ECParameters expected = EccTestData.GetNistP256ReferenceKey();
EccTestBase.ComparePublicKey(expected.Q, ecParameters.Q, isEqual: true);
}
}
[Fact]
public void ImportFromPem_Spki_PrecedingUnrelatedPemIsIgnored()
{
using (TAlg key = CreateKey())
{
key.ImportFromPem(@"
-----BEGIN CERTIFICATE-----
MIICTzCCAgmgAwIBAgIJAMQtYhFJ0+5jMA0GCSqGSIb3DQEBBQUAMIGSMQswCQYD
VQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjEQMA4GA1UEBwwHUmVkbW9uZDEY
MBYGA1UECgwPTWljcm9zb2Z0IENvcnAuMSAwHgYDVQQLDBcuTkVUIEZyYW1ld29y
ayAoQ29yZUZ4KTEgMB4GA1UEAwwXUlNBIDM4NC1iaXQgQ2VydGlmaWNhdGUwHhcN
MTYwMzAyMTY1OTA0WhcNMTYwNDAxMTY1OTA0WjCBkjELMAkGA1UEBhMCVVMxEzAR
BgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1JlZG1vbmQxGDAWBgNVBAoMD01p
Y3Jvc29mdCBDb3JwLjEgMB4GA1UECwwXLk5FVCBGcmFtZXdvcmsgKENvcmVGeCkx
IDAeBgNVBAMMF1JTQSAzODQtYml0IENlcnRpZmljYXRlMEwwDQYJKoZIhvcNAQEB
BQADOwAwOAIxANrMIthuZxV1Ay4x8gbc/BksZeLVEInlES0JbyiCr9tbeM22Vy/S
9h2zkEciMuPZ9QIDAQABo1AwTjAdBgNVHQ4EFgQU5FG2Fmi86hJOCf4KnjaxOGWV
dRUwHwYDVR0jBBgwFoAU5FG2Fmi86hJOCf4KnjaxOGWVdRUwDAYDVR0TBAUwAwEB
/zANBgkqhkiG9w0BAQUFAAMxAEzDg/u8TlApCnE8qxhcbTXk2MbX+2n5PCn+MVrW
wggvPj3b2WMXsVWiPr4S1Y/nBA==
-----END CERTIFICATE-----
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEgQHs5HRkpurXDPaabivT2IaRoyYt
Isuk92Ner/JmgKjYoSumHVmSNfZ9nLTVjxeD08pD548KWrqmJAeZNsDDqQ==
-----END PUBLIC KEY-----");
ECParameters ecParameters = ExportParameters(key, false);
ECParameters expected = EccTestData.GetNistP256ReferenceKey();
EccTestBase.ComparePublicKey(expected.Q, ecParameters.Q, isEqual: true);
}
}
[Fact]
public void ImportFromPem_Spki_IgnoresUnrelatedAlgorithms()
{
using (TAlg key = CreateKey())
{
key.ImportFromPem(@"
-----BEGIN RSA PRIVATE KEY-----
MIIBOwIBAAJBALc/WfXui9VeJLf/AprRaoVDyW0lPlQxm5NTLEHDwUd7idstLzPX
uah0WEjgao5oO1BEUR4byjYlJ+F89Cs4BhUCAwEAAQJBAK/m8jYvnK9exaSR+DAh
Ij12ip5pB+HOFOdhCbS/coNoIowa6WJGrd3Np1m9BBhouWloF8UB6Iu8/e/wAg+F
9ykCIQDzcnsehnYgVZTTxzoCJ01PGpgESilRyFzNEsb8V60ZewIhAMCyOujqUqn7
Q079SlHzXuvocqIdt4IM1EmIlrlU9GGvAh8Ijv3FFPUSLfANgfOIH9mX7ldpzzGk
rmaUzxQvyuVLAiEArCTM8dSbopUADWnD4jArhU50UhWAIaM6ZrKqC8k0RKsCIQDC
yZWUxoxAdjfrBGsx+U6BHM0Myqqe7fY7hjWzj4aBCw==
-----END RSA PRIVATE KEY-----
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEgQHs5HRkpurXDPaabivT2IaRoyYt
Isuk92Ner/JmgKjYoSumHVmSNfZ9nLTVjxeD08pD548KWrqmJAeZNsDDqQ==
-----END PUBLIC KEY-----");
ECParameters ecParameters = ExportParameters(key, false);
ECParameters expected = EccTestData.GetNistP256ReferenceKey();
EccTestBase.ComparePublicKey(expected.Q, ecParameters.Q, isEqual: true);
}
}
[Fact]
public void ImportFromPem_Spki_PrecedingMalformedPem()
{
using (TAlg key = CreateKey())
{
key.ImportFromPem(@"
-----BEGIN CERTIFICATE-----
$$ I AM NOT A PEM
-----END CERTIFICATE-----
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEgQHs5HRkpurXDPaabivT2IaRoyYt
Isuk92Ner/JmgKjYoSumHVmSNfZ9nLTVjxeD08pD548KWrqmJAeZNsDDqQ==
-----END PUBLIC KEY-----");
ECParameters ecParameters = ExportParameters(key, false);
ECParameters expected = EccTestData.GetNistP256ReferenceKey();
EccTestBase.ComparePublicKey(expected.Q, ecParameters.Q, isEqual: true);
}
}
[Fact]
public void ImportFromPem_Spki_AmbiguousKey_Spki()
{
using (TAlg key = CreateKey())
{
string pem = @"
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEgQHs5HRkpurXDPaabivT2IaRoyYt
Isuk92Ner/JmgKjYoSumHVmSNfZ9nLTVjxeD08pD548KWrqmJAeZNsDDqQ==
-----END PUBLIC KEY-----
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEgQHs5HRkpurXDPaabivT2IaRoyYt
Isuk92Ner/JmgKjYoSumHVmSNfZ9nLTVjxeD08pD548KWrqmJAeZNsDDqQ==
-----END PUBLIC KEY-----";
ArgumentException ae = AssertExtensions.Throws<ArgumentException>("input", () => key.ImportFromPem(pem));
Assert.Contains(AmbiguousExceptionMarker, ae.Message);
}
}
[Fact]
public void ImportFromPem_Spki_AmbiguousKey_EncryptedPkcs8()
{
using (TAlg key = CreateKey())
{
string pem = @"
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIHgMEsGCSqGSIb3DQEFDTA+MCkGCSqGSIb3DQEFDDAcBAjVvm4KTLb0JgICCAAw
DAYIKoZIhvcNAgkFADARBgUrDgMCBwQIuHgfok8Ytl0EgZDkDSJ9vt8UvSesdyV+
Evt9yfvEjiP/6yITq59drw1Kcgp6buOCVCY7LZ06aD6WpogiqGDYMuzfvqg5hNFp
opSAJ/pvHONL5kyAJLeNyG9c/mR2qyrP2L9gL0Z5fB9NyPejKTLi0PXMGQWdDTH8
Qh0fqdrNovgFLubbJFMQN/MwwIAfIuf0Mn0WFYYeQiBJ3kg=
-----END ENCRYPTED PRIVATE KEY-----
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEgQHs5HRkpurXDPaabivT2IaRoyYt
Isuk92Ner/JmgKjYoSumHVmSNfZ9nLTVjxeD08pD548KWrqmJAeZNsDDqQ==
-----END PUBLIC KEY-----";
ArgumentException ae = AssertExtensions.Throws<ArgumentException>("input", () => key.ImportFromPem(pem));
Assert.Contains(AmbiguousExceptionMarker, ae.Message);
}
}
[Fact]
public void ImportFromPem_Spki_AmbiguousKey_EncryptedPkcs8_Pkcs8First()
{
using (TAlg key = CreateKey())
{
string pem = @"
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEgQHs5HRkpurXDPaabivT2IaRoyYt
Isuk92Ner/JmgKjYoSumHVmSNfZ9nLTVjxeD08pD548KWrqmJAeZNsDDqQ==
-----END PUBLIC KEY-----
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIHgMEsGCSqGSIb3DQEFDTA+MCkGCSqGSIb3DQEFDDAcBAjVvm4KTLb0JgICCAAw
DAYIKoZIhvcNAgkFADARBgUrDgMCBwQIuHgfok8Ytl0EgZDkDSJ9vt8UvSesdyV+
Evt9yfvEjiP/6yITq59drw1Kcgp6buOCVCY7LZ06aD6WpogiqGDYMuzfvqg5hNFp
opSAJ/pvHONL5kyAJLeNyG9c/mR2qyrP2L9gL0Z5fB9NyPejKTLi0PXMGQWdDTH8
Qh0fqdrNovgFLubbJFMQN/MwwIAfIuf0Mn0WFYYeQiBJ3kg=
-----END ENCRYPTED PRIVATE KEY-----";
ArgumentException ae = AssertExtensions.Throws<ArgumentException>("input", () => key.ImportFromPem(pem));
Assert.Contains(AmbiguousExceptionMarker, ae.Message);
}
}
[Fact]
public void ImportFromPem_EncryptedPrivateKeyFails()
{
using (TAlg key = CreateKey())
{
string pem = @"
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIHgMEsGCSqGSIb3DQEFDTA+MCkGCSqGSIb3DQEFDDAcBAjVvm4KTLb0JgICCAAw
DAYIKoZIhvcNAgkFADARBgUrDgMCBwQIuHgfok8Ytl0EgZDkDSJ9vt8UvSesdyV+
Evt9yfvEjiP/6yITq59drw1Kcgp6buOCVCY7LZ06aD6WpogiqGDYMuzfvqg5hNFp
opSAJ/pvHONL5kyAJLeNyG9c/mR2qyrP2L9gL0Z5fB9NyPejKTLi0PXMGQWdDTH8
Qh0fqdrNovgFLubbJFMQN/MwwIAfIuf0Mn0WFYYeQiBJ3kg=
-----END ENCRYPTED PRIVATE KEY-----";
ArgumentException ae = AssertExtensions.Throws<ArgumentException>("input", () => key.ImportFromPem(pem));
Assert.Contains(EncryptedExceptionMarker, ae.Message);
}
}
[Fact]
public void ImportFromPem_MultipleEncryptedPrivateKeyAreAmbiguous()
{
using (TAlg key = CreateKey())
{
string pem = @"
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIHgMEsGCSqGSIb3DQEFDTA+MCkGCSqGSIb3DQEFDDAcBAjVvm4KTLb0JgICCAAw
DAYIKoZIhvcNAgkFADARBgUrDgMCBwQIuHgfok8Ytl0EgZDkDSJ9vt8UvSesdyV+
Evt9yfvEjiP/6yITq59drw1Kcgp6buOCVCY7LZ06aD6WpogiqGDYMuzfvqg5hNFp
opSAJ/pvHONL5kyAJLeNyG9c/mR2qyrP2L9gL0Z5fB9NyPejKTLi0PXMGQWdDTH8
Qh0fqdrNovgFLubbJFMQN/MwwIAfIuf0Mn0WFYYeQiBJ3kg=
-----END ENCRYPTED PRIVATE KEY-----
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIHgMEsGCSqGSIb3DQEFDTA+MCkGCSqGSIb3DQEFDDAcBAjVvm4KTLb0JgICCAAw
DAYIKoZIhvcNAgkFADARBgUrDgMCBwQIuHgfok8Ytl0EgZDkDSJ9vt8UvSesdyV+
Evt9yfvEjiP/6yITq59drw1Kcgp6buOCVCY7LZ06aD6WpogiqGDYMuzfvqg5hNFp
opSAJ/pvHONL5kyAJLeNyG9c/mR2qyrP2L9gL0Z5fB9NyPejKTLi0PXMGQWdDTH8
Qh0fqdrNovgFLubbJFMQN/MwwIAfIuf0Mn0WFYYeQiBJ3kg=
-----END ENCRYPTED PRIVATE KEY-----";
ArgumentException ae = AssertExtensions.Throws<ArgumentException>("input", () => key.ImportFromPem(pem));
Assert.Contains(AmbiguousExceptionMarker, ae.Message);
}
}
[Fact]
public void ImportFromEncryptedPem_Pkcs8_Char_Simple()
{
using (TAlg key = CreateKey())
{
string pem = @"
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIHgMEsGCSqGSIb3DQEFDTA+MCkGCSqGSIb3DQEFDDAcBAjVvm4KTLb0JgICCAAw
DAYIKoZIhvcNAgkFADARBgUrDgMCBwQIuHgfok8Ytl0EgZDkDSJ9vt8UvSesdyV+
Evt9yfvEjiP/6yITq59drw1Kcgp6buOCVCY7LZ06aD6WpogiqGDYMuzfvqg5hNFp
opSAJ/pvHONL5kyAJLeNyG9c/mR2qyrP2L9gL0Z5fB9NyPejKTLi0PXMGQWdDTH8
Qh0fqdrNovgFLubbJFMQN/MwwIAfIuf0Mn0WFYYeQiBJ3kg=
-----END ENCRYPTED PRIVATE KEY-----";
key.ImportFromEncryptedPem(pem, "test");
ECParameters ecParameters = ExportParameters(key, true);
ECParameters expected = EccTestData.GetNistP256ReferenceKey();
EccTestBase.AssertEqual(expected, ecParameters);
}
}
[Fact]
public void ImportFromEncryptedPem_Pkcs8_Byte_Simple()
{
using (TAlg key = CreateKey())
{
string pem = @"
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIHsMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAgf9krO2ZiPvAICCAAw
DAYIKoZIhvcNAgkFADAdBglghkgBZQMEAQIEEEv4Re1ATH9lHzx+13GoZU0EgZAV
iE/+pIb/4quf+Y524bXUKTGYXzdSUE8Dp1qdZFcwDiCYCTtpL+065fGhmf1KZS2c
/OMt/tWvtMSj17+dJvShsu/NYJXF5fsfpSJbd3e50Y3AisW0Ob7mmF54KBfg6Y+4
aATwwQdUIKVzUZsQctsHPjbriQKKn7GKSyUOikBUNQ+TozojX8/g7JAsl+T9jGM=
-----END ENCRYPTED PRIVATE KEY-----";
byte[] passwordBytes = Encoding.UTF8.GetBytes("test");
key.ImportFromEncryptedPem(pem, passwordBytes);
ECParameters ecParameters = ExportParameters(key, true);
ECParameters expected = EccTestData.GetNistP256ReferenceKey();
EccTestBase.AssertEqual(expected, ecParameters);
}
}
[Fact]
public void ImportFromEncryptedPem_AmbiguousPem_Byte()
{
using (TAlg key = CreateKey())
{
string pem = @"
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIHsMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAgf9krO2ZiPvAICCAAw
DAYIKoZIhvcNAgkFADAdBglghkgBZQMEAQIEEEv4Re1ATH9lHzx+13GoZU0EgZAV
iE/+pIb/4quf+Y524bXUKTGYXzdSUE8Dp1qdZFcwDiCYCTtpL+065fGhmf1KZS2c
/OMt/tWvtMSj17+dJvShsu/NYJXF5fsfpSJbd3e50Y3AisW0Ob7mmF54KBfg6Y+4
aATwwQdUIKVzUZsQctsHPjbriQKKn7GKSyUOikBUNQ+TozojX8/g7JAsl+T9jGM=
-----END ENCRYPTED PRIVATE KEY-----
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIHgMEsGCSqGSIb3DQEFDTA+MCkGCSqGSIb3DQEFDDAcBAjVvm4KTLb0JgICCAAw
DAYIKoZIhvcNAgkFADARBgUrDgMCBwQIuHgfok8Ytl0EgZDkDSJ9vt8UvSesdyV+
Evt9yfvEjiP/6yITq59drw1Kcgp6buOCVCY7LZ06aD6WpogiqGDYMuzfvqg5hNFp
opSAJ/pvHONL5kyAJLeNyG9c/mR2qyrP2L9gL0Z5fB9NyPejKTLi0PXMGQWdDTH8
Qh0fqdrNovgFLubbJFMQN/MwwIAfIuf0Mn0WFYYeQiBJ3kg=
-----END ENCRYPTED PRIVATE KEY-----";
byte[] passwordBytes = Encoding.UTF8.GetBytes("test");
ArgumentException ae = AssertExtensions.Throws<ArgumentException>("input", () =>
key.ImportFromEncryptedPem(pem, passwordBytes));
Assert.Contains(AmbiguousExceptionMarker, ae.Message);
}
}
[Fact]
public void ImportFromEncryptedPem_AmbiguousPem_Char()
{
using (TAlg key = CreateKey())
{
string pem = @"
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIHsMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAgf9krO2ZiPvAICCAAw
DAYIKoZIhvcNAgkFADAdBglghkgBZQMEAQIEEEv4Re1ATH9lHzx+13GoZU0EgZAV
iE/+pIb/4quf+Y524bXUKTGYXzdSUE8Dp1qdZFcwDiCYCTtpL+065fGhmf1KZS2c
/OMt/tWvtMSj17+dJvShsu/NYJXF5fsfpSJbd3e50Y3AisW0Ob7mmF54KBfg6Y+4
aATwwQdUIKVzUZsQctsHPjbriQKKn7GKSyUOikBUNQ+TozojX8/g7JAsl+T9jGM=
-----END ENCRYPTED PRIVATE KEY-----
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIHgMEsGCSqGSIb3DQEFDTA+MCkGCSqGSIb3DQEFDDAcBAjVvm4KTLb0JgICCAAw
DAYIKoZIhvcNAgkFADARBgUrDgMCBwQIuHgfok8Ytl0EgZDkDSJ9vt8UvSesdyV+
Evt9yfvEjiP/6yITq59drw1Kcgp6buOCVCY7LZ06aD6WpogiqGDYMuzfvqg5hNFp
opSAJ/pvHONL5kyAJLeNyG9c/mR2qyrP2L9gL0Z5fB9NyPejKTLi0PXMGQWdDTH8
Qh0fqdrNovgFLubbJFMQN/MwwIAfIuf0Mn0WFYYeQiBJ3kg=
-----END ENCRYPTED PRIVATE KEY-----";
ArgumentException ae = AssertExtensions.Throws<ArgumentException>("input", () =>
key.ImportFromEncryptedPem(pem, ""));
Assert.Contains(AmbiguousExceptionMarker, ae.Message);
}
}
[Fact]
public void ImportFromEncryptedPem_UnencryptedPem_ThrowsNoPem()
{
using (TAlg key = CreateKey())
{
string pem = @"
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgcKEsLbFoRe1W/2jP
whpHKz8E19aFG/Y0ny19WzRSs4qhRANCAASBAezkdGSm6tcM9ppuK9PYhpGjJi0i
y6T3Y16v8maAqNihK6YdWZI19n2ctNWPF4PTykPnjwpauqYkB5k2wMOp
-----END PRIVATE KEY-----";
byte[] passwordBytes = Array.Empty<byte>();
ArgumentException ae = AssertExtensions.Throws<ArgumentException>("input", () =>
key.ImportFromEncryptedPem(pem, passwordBytes));
Assert.Contains(NoPemExceptionMarker, ae.Message);
}
}
[Fact]
public void ImportFromEncryptedPem_NoPem()
{
using(TAlg key = CreateKey())
{
ArgumentException ae = AssertExtensions.Throws<ArgumentException>("input", () =>
key.ImportFromEncryptedPem("", ""));
Assert.Contains(NoPemExceptionMarker, ae.Message);
}
}
}
}

View file

@ -0,0 +1,15 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Security.Cryptography.Tests;
namespace System.Security.Cryptography.EcDsa.Tests
{
public sealed class ECDiffieHellmanKeyPemTests : ECKeyPemTests<ECDiffieHellman>
{
protected override ECDiffieHellman CreateKey() => ECDiffieHellman.Create();
protected override ECParameters ExportParameters(ECDiffieHellman key, bool includePrivateParameters) =>
key.ExportParameters(includePrivateParameters);
}
}

View file

@ -0,0 +1,15 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Security.Cryptography.Tests;
namespace System.Security.Cryptography.EcDsa.Tests
{
public sealed class ECDsaKeyPemTests : ECKeyPemTests<ECDsa>
{
protected override ECDsa CreateKey() => ECDsa.Create();
protected override ECParameters ExportParameters(ECDsa key, bool includePrivateParameters) =>
key.ExportParameters(includePrivateParameters);
}
}

View file

@ -0,0 +1,530 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Text;
using Test.Cryptography;
using Xunit;
namespace System.Security.Cryptography.Rsa.Tests
{
public static class RSAKeyPemTests
{
private const string AmbiguousExceptionMarker = "multiple keys";
private const string EncryptedExceptionMarker = "encrypted key";
private const string NoPemExceptionMarker = "No supported key";
[Fact]
public static void ImportFromPem_NoPem()
{
using (RSA rsa = RSAFactory.Create())
{
string pem = @"these aren't the PEMs you're looking for";
ArgumentException ae = AssertExtensions.Throws<ArgumentException>("input", () => rsa.ImportFromPem(pem));
Assert.Contains(NoPemExceptionMarker, ae.Message);
}
}
[Fact]
public static void ImportFromPem_RSAPrivateKey_Simple()
{
using (RSA rsa = RSAFactory.Create())
{
string pem = @"
-----BEGIN RSA PRIVATE KEY-----
MIIBOwIBAAJBALc/WfXui9VeJLf/AprRaoVDyW0lPlQxm5NTLEHDwUd7idstLzPX
uah0WEjgao5oO1BEUR4byjYlJ+F89Cs4BhUCAwEAAQJBAK/m8jYvnK9exaSR+DAh
Ij12ip5pB+HOFOdhCbS/coNoIowa6WJGrd3Np1m9BBhouWloF8UB6Iu8/e/wAg+F
9ykCIQDzcnsehnYgVZTTxzoCJ01PGpgESilRyFzNEsb8V60ZewIhAMCyOujqUqn7
Q079SlHzXuvocqIdt4IM1EmIlrlU9GGvAh8Ijv3FFPUSLfANgfOIH9mX7ldpzzGk
rmaUzxQvyuVLAiEArCTM8dSbopUADWnD4jArhU50UhWAIaM6ZrKqC8k0RKsCIQDC
yZWUxoxAdjfrBGsx+U6BHM0Myqqe7fY7hjWzj4aBCw==
-----END RSA PRIVATE KEY-----";
rsa.ImportFromPem(pem);
RSAParameters rsaParameters = rsa.ExportParameters(true);
ImportExport.AssertKeyEquals(TestData.DiminishedDPParameters, rsaParameters);
}
}
[Fact]
public static void ImportFromPem_Pkcs8UnEncrypted_Simple()
{
using (RSA rsa = RSAFactory.Create())
{
string pem = @"
-----BEGIN PRIVATE KEY-----
MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAtz9Z9e6L1V4kt/8C
mtFqhUPJbSU+VDGbk1MsQcPBR3uJ2y0vM9e5qHRYSOBqjmg7UERRHhvKNiUn4Xz0
KzgGFQIDAQABAkEAr+byNi+cr17FpJH4MCEiPXaKnmkH4c4U52EJtL9yg2gijBrp
Ykat3c2nWb0EGGi5aWgXxQHoi7z97/ACD4X3KQIhAPNyex6GdiBVlNPHOgInTU8a
mARKKVHIXM0SxvxXrRl7AiEAwLI66OpSqftDTv1KUfNe6+hyoh23ggzUSYiWuVT0
Ya8CHwiO/cUU9RIt8A2B84gf2ZfuV2nPMaSuZpTPFC/K5UsCIQCsJMzx1JuilQAN
acPiMCuFTnRSFYAhozpmsqoLyTREqwIhAMLJlZTGjEB2N+sEazH5ToEczQzKqp7t
9juGNbOPhoEL
-----END PRIVATE KEY-----";
rsa.ImportFromPem(pem);
RSAParameters rsaParameters = rsa.ExportParameters(true);
ImportExport.AssertKeyEquals(TestData.DiminishedDPParameters, rsaParameters);
}
}
[Fact]
public static void ImportFromPem_Pkcs8UnEncrypted_UnrelatedAlgorithmIsIgnored()
{
using (RSA rsa = RSAFactory.Create())
{
string pem = @"
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIHChLC2xaEXtVv9oz8IaRys/BNfWhRv2NJ8tfVs0UrOKoAoGCCqGSM49
AwEHoUQDQgAEgQHs5HRkpurXDPaabivT2IaRoyYtIsuk92Ner/JmgKjYoSumHVmS
NfZ9nLTVjxeD08pD548KWrqmJAeZNsDDqQ==
-----END EC PRIVATE KEY-----
-----BEGIN PRIVATE KEY-----
MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAtz9Z9e6L1V4kt/8C
mtFqhUPJbSU+VDGbk1MsQcPBR3uJ2y0vM9e5qHRYSOBqjmg7UERRHhvKNiUn4Xz0
KzgGFQIDAQABAkEAr+byNi+cr17FpJH4MCEiPXaKnmkH4c4U52EJtL9yg2gijBrp
Ykat3c2nWb0EGGi5aWgXxQHoi7z97/ACD4X3KQIhAPNyex6GdiBVlNPHOgInTU8a
mARKKVHIXM0SxvxXrRl7AiEAwLI66OpSqftDTv1KUfNe6+hyoh23ggzUSYiWuVT0
Ya8CHwiO/cUU9RIt8A2B84gf2ZfuV2nPMaSuZpTPFC/K5UsCIQCsJMzx1JuilQAN
acPiMCuFTnRSFYAhozpmsqoLyTREqwIhAMLJlZTGjEB2N+sEazH5ToEczQzKqp7t
9juGNbOPhoEL
-----END PRIVATE KEY-----";
rsa.ImportFromPem(pem);
RSAParameters rsaParameters = rsa.ExportParameters(true);
ImportExport.AssertKeyEquals(TestData.DiminishedDPParameters, rsaParameters);
}
}
[Fact]
public static void ImportFromPem_SubjectPublicKeyInfo_Simple()
{
using (RSA rsa = RSAFactory.Create())
{
string pem = @"
-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALc/WfXui9VeJLf/AprRaoVDyW0lPlQx
m5NTLEHDwUd7idstLzPXuah0WEjgao5oO1BEUR4byjYlJ+F89Cs4BhUCAwEAAQ==
-----END PUBLIC KEY-----";
rsa.ImportFromPem(pem);
RSAParameters rsaParameters = rsa.ExportParameters(false);
ImportExport.AssertKeyEquals(TestData.DiminishedDPParameters.ToPublic(), rsaParameters);
}
}
[Fact]
public static void ImportFromPem_SubjectPublicKeyInfo_IgnoresUnrelatedAlgorithm()
{
using (RSA rsa = RSAFactory.Create())
{
string pem = @"
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIHChLC2xaEXtVv9oz8IaRys/BNfWhRv2NJ8tfVs0UrOKoAoGCCqGSM49
AwEHoUQDQgAEgQHs5HRkpurXDPaabivT2IaRoyYtIsuk92Ner/JmgKjYoSumHVmS
NfZ9nLTVjxeD08pD548KWrqmJAeZNsDDqQ==
-----END EC PRIVATE KEY-----
-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALc/WfXui9VeJLf/AprRaoVDyW0lPlQx
m5NTLEHDwUd7idstLzPXuah0WEjgao5oO1BEUR4byjYlJ+F89Cs4BhUCAwEAAQ==
-----END PUBLIC KEY-----";
rsa.ImportFromPem(pem);
RSAParameters rsaParameters = rsa.ExportParameters(false);
ImportExport.AssertKeyEquals(TestData.DiminishedDPParameters.ToPublic(), rsaParameters);
}
}
[Fact]
public static void ImportFromPem_RSAPublicKey_Simple()
{
using (RSA rsa = RSAFactory.Create())
{
string pem = @"
-----BEGIN RSA PUBLIC KEY-----
MEgCQQC3P1n17ovVXiS3/wKa0WqFQ8ltJT5UMZuTUyxBw8FHe4nbLS8z17modFhI
4GqOaDtQRFEeG8o2JSfhfPQrOAYVAgMBAAE=
-----END RSA PUBLIC KEY-----";
rsa.ImportFromPem(pem);
RSAParameters rsaParameters = rsa.ExportParameters(false);
ImportExport.AssertKeyEquals(TestData.DiminishedDPParameters.ToPublic(), rsaParameters);
}
}
[Fact]
public static void ImportFromPem_RSAPrivateKey_PrecedingUnrelatedPem()
{
using (RSA rsa = RSAFactory.Create())
{
string pem = @"
-----BEGIN CERTIFICATE-----
MIICTzCCAgmgAwIBAgIJAMQtYhFJ0+5jMA0GCSqGSIb3DQEBBQUAMIGSMQswCQYD
VQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjEQMA4GA1UEBwwHUmVkbW9uZDEY
MBYGA1UECgwPTWljcm9zb2Z0IENvcnAuMSAwHgYDVQQLDBcuTkVUIEZyYW1ld29y
ayAoQ29yZUZ4KTEgMB4GA1UEAwwXUlNBIDM4NC1iaXQgQ2VydGlmaWNhdGUwHhcN
MTYwMzAyMTY1OTA0WhcNMTYwNDAxMTY1OTA0WjCBkjELMAkGA1UEBhMCVVMxEzAR
BgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1JlZG1vbmQxGDAWBgNVBAoMD01p
Y3Jvc29mdCBDb3JwLjEgMB4GA1UECwwXLk5FVCBGcmFtZXdvcmsgKENvcmVGeCkx
IDAeBgNVBAMMF1JTQSAzODQtYml0IENlcnRpZmljYXRlMEwwDQYJKoZIhvcNAQEB
BQADOwAwOAIxANrMIthuZxV1Ay4x8gbc/BksZeLVEInlES0JbyiCr9tbeM22Vy/S
9h2zkEciMuPZ9QIDAQABo1AwTjAdBgNVHQ4EFgQU5FG2Fmi86hJOCf4KnjaxOGWV
dRUwHwYDVR0jBBgwFoAU5FG2Fmi86hJOCf4KnjaxOGWVdRUwDAYDVR0TBAUwAwEB
/zANBgkqhkiG9w0BAQUFAAMxAEzDg/u8TlApCnE8qxhcbTXk2MbX+2n5PCn+MVrW
wggvPj3b2WMXsVWiPr4S1Y/nBA==
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
MIIBOwIBAAJBALc/WfXui9VeJLf/AprRaoVDyW0lPlQxm5NTLEHDwUd7idstLzPX
uah0WEjgao5oO1BEUR4byjYlJ+F89Cs4BhUCAwEAAQJBAK/m8jYvnK9exaSR+DAh
Ij12ip5pB+HOFOdhCbS/coNoIowa6WJGrd3Np1m9BBhouWloF8UB6Iu8/e/wAg+F
9ykCIQDzcnsehnYgVZTTxzoCJ01PGpgESilRyFzNEsb8V60ZewIhAMCyOujqUqn7
Q079SlHzXuvocqIdt4IM1EmIlrlU9GGvAh8Ijv3FFPUSLfANgfOIH9mX7ldpzzGk
rmaUzxQvyuVLAiEArCTM8dSbopUADWnD4jArhU50UhWAIaM6ZrKqC8k0RKsCIQDC
yZWUxoxAdjfrBGsx+U6BHM0Myqqe7fY7hjWzj4aBCw==
-----END RSA PRIVATE KEY-----";
rsa.ImportFromPem(pem);
RSAParameters rsaParameters = rsa.ExportParameters(true);
ImportExport.AssertKeyEquals(TestData.DiminishedDPParameters, rsaParameters);
}
}
[Fact]
public static void ImportFromPem_RSAPrivateKey_PrecedingMalformedPem()
{
using (RSA rsa = RSAFactory.Create())
{
string pem = @"
-----BEGIN CERTIFICATE-----
$$ I AM NOT A PEM
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
MIIBOwIBAAJBALc/WfXui9VeJLf/AprRaoVDyW0lPlQxm5NTLEHDwUd7idstLzPX
uah0WEjgao5oO1BEUR4byjYlJ+F89Cs4BhUCAwEAAQJBAK/m8jYvnK9exaSR+DAh
Ij12ip5pB+HOFOdhCbS/coNoIowa6WJGrd3Np1m9BBhouWloF8UB6Iu8/e/wAg+F
9ykCIQDzcnsehnYgVZTTxzoCJ01PGpgESilRyFzNEsb8V60ZewIhAMCyOujqUqn7
Q079SlHzXuvocqIdt4IM1EmIlrlU9GGvAh8Ijv3FFPUSLfANgfOIH9mX7ldpzzGk
rmaUzxQvyuVLAiEArCTM8dSbopUADWnD4jArhU50UhWAIaM6ZrKqC8k0RKsCIQDC
yZWUxoxAdjfrBGsx+U6BHM0Myqqe7fY7hjWzj4aBCw==
-----END RSA PRIVATE KEY-----";
rsa.ImportFromPem(pem);
RSAParameters rsaParameters = rsa.ExportParameters(true);
ImportExport.AssertKeyEquals(TestData.DiminishedDPParameters, rsaParameters);
}
}
[Fact]
public static void ImportFromPem_RSAPrivateKey_IgnoresOtherAlgorithms()
{
using (RSA rsa = RSAFactory.Create())
{
string pem = @"
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIHChLC2xaEXtVv9oz8IaRys/BNfWhRv2NJ8tfVs0UrOKoAoGCCqGSM49
AwEHoUQDQgAEgQHs5HRkpurXDPaabivT2IaRoyYtIsuk92Ner/JmgKjYoSumHVmS
NfZ9nLTVjxeD08pD548KWrqmJAeZNsDDqQ==
-----END EC PRIVATE KEY-----
-----BEGIN RSA PRIVATE KEY-----
MIIBOwIBAAJBALc/WfXui9VeJLf/AprRaoVDyW0lPlQxm5NTLEHDwUd7idstLzPX
uah0WEjgao5oO1BEUR4byjYlJ+F89Cs4BhUCAwEAAQJBAK/m8jYvnK9exaSR+DAh
Ij12ip5pB+HOFOdhCbS/coNoIowa6WJGrd3Np1m9BBhouWloF8UB6Iu8/e/wAg+F
9ykCIQDzcnsehnYgVZTTxzoCJ01PGpgESilRyFzNEsb8V60ZewIhAMCyOujqUqn7
Q079SlHzXuvocqIdt4IM1EmIlrlU9GGvAh8Ijv3FFPUSLfANgfOIH9mX7ldpzzGk
rmaUzxQvyuVLAiEArCTM8dSbopUADWnD4jArhU50UhWAIaM6ZrKqC8k0RKsCIQDC
yZWUxoxAdjfrBGsx+U6BHM0Myqqe7fY7hjWzj4aBCw==
-----END RSA PRIVATE KEY-----";
rsa.ImportFromPem(pem);
RSAParameters rsaParameters = rsa.ExportParameters(true);
ImportExport.AssertKeyEquals(TestData.DiminishedDPParameters, rsaParameters);
}
}
[Fact]
public static void ImportFromPem_RSAPrivateKey_AmbiguousKey_RSAPrivateKey()
{
using (RSA rsa = RSAFactory.Create())
{
string pem = @"
-----BEGIN RSA PRIVATE KEY-----
MII=
-----END RSA PRIVATE KEY-----
-----BEGIN RSA PRIVATE KEY-----
MIIBOwIBAAJBALc/WfXui9VeJLf/AprRaoVDyW0lPlQxm5NTLEHDwUd7idstLzPX
uah0WEjgao5oO1BEUR4byjYlJ+F89Cs4BhUCAwEAAQJBAK/m8jYvnK9exaSR+DAh
Ij12ip5pB+HOFOdhCbS/coNoIowa6WJGrd3Np1m9BBhouWloF8UB6Iu8/e/wAg+F
9ykCIQDzcnsehnYgVZTTxzoCJ01PGpgESilRyFzNEsb8V60ZewIhAMCyOujqUqn7
Q079SlHzXuvocqIdt4IM1EmIlrlU9GGvAh8Ijv3FFPUSLfANgfOIH9mX7ldpzzGk
rmaUzxQvyuVLAiEArCTM8dSbopUADWnD4jArhU50UhWAIaM6ZrKqC8k0RKsCIQDC
yZWUxoxAdjfrBGsx+U6BHM0Myqqe7fY7hjWzj4aBCw==
-----END RSA PRIVATE KEY-----";
ArgumentException ae = AssertExtensions.Throws<ArgumentException>("input", () => rsa.ImportFromPem(pem));
Assert.Contains(AmbiguousExceptionMarker, ae.Message);
}
}
[Fact]
public static void ImportFromPem_RSAPrivateKey_AmbiguousKey_SubjectPublicKeyInfo()
{
using (RSA rsa = RSAFactory.Create())
{
string pem = @"
-----BEGIN PUBLIC KEY-----
MII=
-----END PUBLIC KEY-----
-----BEGIN RSA PRIVATE KEY-----
MIIBOwIBAAJBALc/WfXui9VeJLf/AprRaoVDyW0lPlQxm5NTLEHDwUd7idstLzPX
uah0WEjgao5oO1BEUR4byjYlJ+F89Cs4BhUCAwEAAQJBAK/m8jYvnK9exaSR+DAh
Ij12ip5pB+HOFOdhCbS/coNoIowa6WJGrd3Np1m9BBhouWloF8UB6Iu8/e/wAg+F
9ykCIQDzcnsehnYgVZTTxzoCJ01PGpgESilRyFzNEsb8V60ZewIhAMCyOujqUqn7
Q079SlHzXuvocqIdt4IM1EmIlrlU9GGvAh8Ijv3FFPUSLfANgfOIH9mX7ldpzzGk
rmaUzxQvyuVLAiEArCTM8dSbopUADWnD4jArhU50UhWAIaM6ZrKqC8k0RKsCIQDC
yZWUxoxAdjfrBGsx+U6BHM0Myqqe7fY7hjWzj4aBCw==
-----END RSA PRIVATE KEY-----";
ArgumentException ae = AssertExtensions.Throws<ArgumentException>("input", () => rsa.ImportFromPem(pem));
Assert.Contains(AmbiguousExceptionMarker, ae.Message);
}
}
[Fact]
public static void ImportFromPem_RSAPrivateKey_AmbiguousKey_RSAPublicKey()
{
using (RSA rsa = RSAFactory.Create())
{
string pem = @"
-----BEGIN RSA PUBLIC KEY-----
MII=
-----END RSA PUBLIC KEY-----
-----BEGIN RSA PRIVATE KEY-----
MIIBOwIBAAJBALc/WfXui9VeJLf/AprRaoVDyW0lPlQxm5NTLEHDwUd7idstLzPX
uah0WEjgao5oO1BEUR4byjYlJ+F89Cs4BhUCAwEAAQJBAK/m8jYvnK9exaSR+DAh
Ij12ip5pB+HOFOdhCbS/coNoIowa6WJGrd3Np1m9BBhouWloF8UB6Iu8/e/wAg+F
9ykCIQDzcnsehnYgVZTTxzoCJ01PGpgESilRyFzNEsb8V60ZewIhAMCyOujqUqn7
Q079SlHzXuvocqIdt4IM1EmIlrlU9GGvAh8Ijv3FFPUSLfANgfOIH9mX7ldpzzGk
rmaUzxQvyuVLAiEArCTM8dSbopUADWnD4jArhU50UhWAIaM6ZrKqC8k0RKsCIQDC
yZWUxoxAdjfrBGsx+U6BHM0Myqqe7fY7hjWzj4aBCw==
-----END RSA PRIVATE KEY-----";
ArgumentException ae = AssertExtensions.Throws<ArgumentException>("input", () => rsa.ImportFromPem(pem));
Assert.Contains(AmbiguousExceptionMarker, ae.Message);
}
}
[Fact]
public static void ImportFromPem_RSAPrivateKey_AmbiguousKey_EncryptedPkcs8()
{
using (RSA rsa = RSAFactory.Create())
{
string pem = @"
-----BEGIN ENCRYPTED PRIVATE KEY-----
MII=
-----END ENCRYPTED PRIVATE KEY-----
-----BEGIN RSA PRIVATE KEY-----
MIIBOwIBAAJBALc/WfXui9VeJLf/AprRaoVDyW0lPlQxm5NTLEHDwUd7idstLzPX
uah0WEjgao5oO1BEUR4byjYlJ+F89Cs4BhUCAwEAAQJBAK/m8jYvnK9exaSR+DAh
Ij12ip5pB+HOFOdhCbS/coNoIowa6WJGrd3Np1m9BBhouWloF8UB6Iu8/e/wAg+F
9ykCIQDzcnsehnYgVZTTxzoCJ01PGpgESilRyFzNEsb8V60ZewIhAMCyOujqUqn7
Q079SlHzXuvocqIdt4IM1EmIlrlU9GGvAh8Ijv3FFPUSLfANgfOIH9mX7ldpzzGk
rmaUzxQvyuVLAiEArCTM8dSbopUADWnD4jArhU50UhWAIaM6ZrKqC8k0RKsCIQDC
yZWUxoxAdjfrBGsx+U6BHM0Myqqe7fY7hjWzj4aBCw==
-----END RSA PRIVATE KEY-----";
ArgumentException ae = AssertExtensions.Throws<ArgumentException>("input", () => rsa.ImportFromPem(pem));
Assert.Contains(AmbiguousExceptionMarker, ae.Message);
}
}
[Fact]
public static void ImportFromPem_EncryptedPrivateKeyFails()
{
using (RSA rsa = RSAFactory.Create())
{
string pem = @"
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIBsTBLBgkqhkiG9w0BBQ0wPjApBgkqhkiG9w0BBQwwHAQIioaQaFwlfasCAggA
MAwGCCqGSIb3DQIJBQAwEQYFKw4DAgcECJLGzSuIgnSkBIIBYHofFpp5AsrkNc9w
s0uebkLBgMXbmhu+t6XQYXhnZXguT4KF4g49vIE3XwtZkXzEeSrNRIWZcPH1UWp2
qbv2d+ub3wBpMdFDzv5Zty6e6gACWwyMRy/oX8gZqWDfDnQwm7BV21yLANEFnRuT
K3c9EmQ9IAT2MLLRUeijyg6KUL0dZ5VmXbtQdDoovuhzU20HjSyQLXNbX8NzUhWy
VMuNHs8NhiIgOuFKMoqlN42LBA1+iOA4MGR5XDXXmGyKPLCs0USbD9Dm4/Q1h7Fs
x2yC94Mej7kgAusuNZk9GafsIQbM7jZT1PLxIKyMXAxIpS9sIYbegxK774npiy8/
LiBC1SQXJ3sJdAeUE0QPJEci937f8SteWUmF5mUqznb/0nYjvSZh/GcZ4GWEAO8j
RkMxT/C7OZVMOlb3HV3fJj7kDmOMqfc6aKEQjLdWtuYRB8CgaudldIpK4jP2+0b5
pBORBb0=
-----END ENCRYPTED PRIVATE KEY-----";
ArgumentException ae = AssertExtensions.Throws<ArgumentException>("input", () => rsa.ImportFromPem(pem));
Assert.Contains(EncryptedExceptionMarker, ae.Message);
}
}
[Fact]
public static void ImportFromPem_Pkcs8AlgorithmMismatch_Throws()
{
using (RSA rsa = RSAFactory.Create())
{
string pem = @"
The below PEM is a 1024-bit DSA key.
-----BEGIN PRIVATE KEY-----
MIIBSgIBADCCASsGByqGSM44BAEwggEeAoGBAL5KGXEaazCA+k1pMcCBc/+bodFh
0P4U2QDLyDtnmytusGPaHcFp69pVdJZWMBycwJdaFQkraQNmqQsjAmBHtpqMeJpE
VLgjzve83oMAw5aysmaQC4Wy35vnBZnshvdzgbPRHZD2dWmFvWxToqBnxh74rb/H
Nkpt8JrirFOdNuyvAhUA9+LZ6XHLZZKeFhDxYl+a9lYabdsCgYACRi+pc9joLRah
A9ushrXVItFyOsq45hOB9hT37nyTEmane/YAjmoR28XyDYdF/Ql97iSVm3cY3OYT
eDr38gQ/Hk0CgW3/RFrNWdbIpfMifs80vqCUNqDggcQixEmDVZ0gwq4+wz8EVyYG
42+vM7ajN4O2VGvCA99Vl6zv69hOpAQWAhQtFFLZyKAUOQwUQh4hNw+oBgPhFw==
-----END PRIVATE KEY-----";
Assert.Throws<CryptographicException>(() => rsa.ImportFromPem(pem));
}
}
[Fact]
public static void ImportFromEncryptedPem_Pkcs8Encrypted_Char_Simple()
{
using (RSA rsa = RSAFactory.Create())
{
string pem = @"
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIBsTBLBgkqhkiG9w0BBQ0wPjApBgkqhkiG9w0BBQwwHAQIcvgI1lw9LqYCAggA
MAwGCCqGSIb3DQIJBQAwEQYFKw4DAgcECFDpLREQXt5pBIIBYOKuM5ljAvCViDL+
nTFq7A/fI9rqdL20TMdf0wy7s43oXmsw5gCStoNEaoVToFCQWYYBRU99mK8YNFA8
1ZJT53SDS7buJ0zX9oDltf2ByXRPI4mn2Il2HZvN2hi9ir1w8M3XoSFSurN9tC8r
IOiGkVfK9Ll54knONewNiCNefFZFctRfVMbac5SwHokCkBMHukl0oPrpVuBE8kRo
p7XtjM8ILtzLVz0iLqKXiNIf6kRdouCBmCn8VIQgIvPPIHD8vheMXWjN7g69P5n4
1YI4c/acljcofmq1BBPTwvxaETrg2NHW0XMIgAxoaVP8lIIGlNk1glWTYpuMd69L
AWvBUt33Sozc+dF0l7NGLAWL2tqkkpyDQuKn6UgYz/vxkFeQAVfSuaJVR+fUlHg0
N4lD7/hJq7b+yYPhlN3Fvvt8M9MtRg1TLAve67CA2v4TITHB06M/ELe3y42bZuLW
CA7ffFk=
-----END ENCRYPTED PRIVATE KEY-----";
rsa.ImportFromEncryptedPem(pem, "test");
RSAParameters rsaParameters = rsa.ExportParameters(true);
ImportExport.AssertKeyEquals(TestData.DiminishedDPParameters, rsaParameters);
}
}
[Fact]
public static void ImportFromEncryptedPem_Pkcs8Encrypted_Byte_Simple()
{
using (RSA rsa = RSAFactory.Create())
{
string pem = @"
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIBvTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIciLWmWb33X0CAggA
MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAECBBBVEmHhJdbi+HKzPttNjXm4BIIB
YFejknurbot2VDXwc671A0mfA0cw/u7K44gsYXcZwAARC8j6f3lSzB0tN2kMEx/L
TB+kpMBbfAoIPKoEc9Y4w9m3NXkQYrLRONh9AFiAnOjULHwkstQfN2ofFlolDfbH
hAE6ga6aQJTQ8rDKTL4QkCg+s+qWlicPqs5ikSQfUz2Qiy8FKe7zZlJ0OWpT+zk7
EYRrUSKQcEAjfNS7anlMps2ZXRc1LkLJNHZSl6h2BuFPfIKEV9REpy3Y7sH7vNZZ
PWPa9/xM4CX/c/ommy6LqvZikUuUGc56/Hbz65SwG3voivIhOTmM28LiA6z0YXmY
E+nr7hyinl51raM1RSHojJB22oOW+GwV7GgWYIjUgIEMDOhN10FcGNfTeC65PCXx
5QSEe7EKVF0aHXBYB5SzMGVuxR/BqydDa26jlhVzO3LNvy9FYuqLKUslCrBCmPrt
raZNyk8KAsLs+FJq9T2tda0=
-----END ENCRYPTED PRIVATE KEY-----";
rsa.ImportFromEncryptedPem(pem, Encoding.UTF8.GetBytes("test"));
RSAParameters rsaParameters = rsa.ExportParameters(true);
ImportExport.AssertKeyEquals(TestData.DiminishedDPParameters, rsaParameters);
}
}
[Fact]
public static void ImportFromEncryptedPem_Pkcs8Encrypted_AmbiguousPem()
{
using (RSA rsa = RSAFactory.Create())
{
string pem = @"
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIBvTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIciLWmWb33X0CAggA
MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAECBBBVEmHhJdbi+HKzPttNjXm4BIIB
YFejknurbot2VDXwc671A0mfA0cw/u7K44gsYXcZwAARC8j6f3lSzB0tN2kMEx/L
TB+kpMBbfAoIPKoEc9Y4w9m3NXkQYrLRONh9AFiAnOjULHwkstQfN2ofFlolDfbH
hAE6ga6aQJTQ8rDKTL4QkCg+s+qWlicPqs5ikSQfUz2Qiy8FKe7zZlJ0OWpT+zk7
EYRrUSKQcEAjfNS7anlMps2ZXRc1LkLJNHZSl6h2BuFPfIKEV9REpy3Y7sH7vNZZ
PWPa9/xM4CX/c/ommy6LqvZikUuUGc56/Hbz65SwG3voivIhOTmM28LiA6z0YXmY
E+nr7hyinl51raM1RSHojJB22oOW+GwV7GgWYIjUgIEMDOhN10FcGNfTeC65PCXx
5QSEe7EKVF0aHXBYB5SzMGVuxR/BqydDa26jlhVzO3LNvy9FYuqLKUslCrBCmPrt
raZNyk8KAsLs+FJq9T2tda0=
-----END ENCRYPTED PRIVATE KEY-----
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIBsTBLBgkqhkiG9w0BBQ0wPjApBgkqhkiG9w0BBQwwHAQIcvgI1lw9LqYCAggA
MAwGCCqGSIb3DQIJBQAwEQYFKw4DAgcECFDpLREQXt5pBIIBYOKuM5ljAvCViDL+
nTFq7A/fI9rqdL20TMdf0wy7s43oXmsw5gCStoNEaoVToFCQWYYBRU99mK8YNFA8
1ZJT53SDS7buJ0zX9oDltf2ByXRPI4mn2Il2HZvN2hi9ir1w8M3XoSFSurN9tC8r
IOiGkVfK9Ll54knONewNiCNefFZFctRfVMbac5SwHokCkBMHukl0oPrpVuBE8kRo
p7XtjM8ILtzLVz0iLqKXiNIf6kRdouCBmCn8VIQgIvPPIHD8vheMXWjN7g69P5n4
1YI4c/acljcofmq1BBPTwvxaETrg2NHW0XMIgAxoaVP8lIIGlNk1glWTYpuMd69L
AWvBUt33Sozc+dF0l7NGLAWL2tqkkpyDQuKn6UgYz/vxkFeQAVfSuaJVR+fUlHg0
N4lD7/hJq7b+yYPhlN3Fvvt8M9MtRg1TLAve67CA2v4TITHB06M/ELe3y42bZuLW
CA7ffFk=
-----END ENCRYPTED PRIVATE KEY-----";
byte[] passwordBytes = Encoding.UTF8.GetBytes("test");
ArgumentException ae = AssertExtensions.Throws<ArgumentException>("input", () =>
rsa.ImportFromEncryptedPem(pem, passwordBytes));
Assert.Contains(AmbiguousExceptionMarker, ae.Message);
}
}
[Fact]
public static void ImportFromEncryptedPem_Pkcs8Encrypted_Byte_NoPem()
{
using (RSA rsa = RSAFactory.Create())
{
string pem = "these aren't the PEMs we're looking for.";
byte[] passwordBytes = Encoding.UTF8.GetBytes("test");
ArgumentException ae = AssertExtensions.Throws<ArgumentException>("input", () =>
rsa.ImportFromEncryptedPem(pem, passwordBytes));
Assert.Contains(NoPemExceptionMarker, ae.Message);
}
}
[Fact]
public static void ImportFromEncryptedPem_NoEncryptedPem()
{
using (RSA rsa = RSAFactory.Create())
{
string pem = @"
-----BEGIN PRIVATE KEY-----
MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAtz9Z9e6L1V4kt/8C
mtFqhUPJbSU+VDGbk1MsQcPBR3uJ2y0vM9e5qHRYSOBqjmg7UERRHhvKNiUn4Xz0
KzgGFQIDAQABAkEAr+byNi+cr17FpJH4MCEiPXaKnmkH4c4U52EJtL9yg2gijBrp
Ykat3c2nWb0EGGi5aWgXxQHoi7z97/ACD4X3KQIhAPNyex6GdiBVlNPHOgInTU8a
mARKKVHIXM0SxvxXrRl7AiEAwLI66OpSqftDTv1KUfNe6+hyoh23ggzUSYiWuVT0
Ya8CHwiO/cUU9RIt8A2B84gf2ZfuV2nPMaSuZpTPFC/K5UsCIQCsJMzx1JuilQAN
acPiMCuFTnRSFYAhozpmsqoLyTREqwIhAMLJlZTGjEB2N+sEazH5ToEczQzKqp7t
9juGNbOPhoEL
-----END PRIVATE KEY-----";
byte[] passwordBytes = Encoding.UTF8.GetBytes("test");
ArgumentException ae = AssertExtensions.Throws<ArgumentException>("input", () =>
rsa.ImportFromEncryptedPem(pem, passwordBytes));
Assert.Contains(NoPemExceptionMarker, ae.Message);
}
}
[Fact]
public static void ImportFromEncryptedPem_Pkcs8Encrypted_Char_NoPem()
{
using (RSA rsa = RSAFactory.Create())
{
string pem = "go about your business";
string password = "test";
ArgumentException ae = AssertExtensions.Throws<ArgumentException>("input", () =>
rsa.ImportFromEncryptedPem(pem, password));
Assert.Contains(NoPemExceptionMarker, ae.Message);
}
}
private static RSAParameters ToPublic(this RSAParameters rsaParams)
{
return new RSAParameters
{
Exponent = rsaParams.Exponent,
Modulus = rsaParams.Modulus
};
}
}
}

View file

@ -135,6 +135,9 @@ namespace System.Security.Cryptography
protected virtual byte[] HashData(System.IO.Stream data, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { throw null; }
public override void ImportEncryptedPkcs8PrivateKey(System.ReadOnlySpan<byte> passwordBytes, System.ReadOnlySpan<byte> source, out int bytesRead) { throw null; }
public override void ImportEncryptedPkcs8PrivateKey(System.ReadOnlySpan<char> password, System.ReadOnlySpan<byte> source, out int bytesRead) { throw null; }
public override void ImportFromEncryptedPem(System.ReadOnlySpan<char> input, System.ReadOnlySpan<byte> passwordBytes) { }
public override void ImportFromEncryptedPem(System.ReadOnlySpan<char> input, System.ReadOnlySpan<char> password) { }
public override void ImportFromPem(System.ReadOnlySpan<char> input) { }
public abstract void ImportParameters(System.Security.Cryptography.DSAParameters parameters);
public override void ImportPkcs8PrivateKey(System.ReadOnlySpan<byte> source, out int bytesRead) { throw null; }
public override void ImportSubjectPublicKeyInfo(System.ReadOnlySpan<byte> source, out int bytesRead) { throw null; }
@ -283,6 +286,9 @@ namespace System.Security.Cryptography
public virtual void ImportECPrivateKey(System.ReadOnlySpan<byte> source, out int bytesRead) { throw null; }
public override void ImportEncryptedPkcs8PrivateKey(System.ReadOnlySpan<byte> passwordBytes, System.ReadOnlySpan<byte> source, out int bytesRead) { throw null; }
public override void ImportEncryptedPkcs8PrivateKey(System.ReadOnlySpan<char> password, System.ReadOnlySpan<byte> source, out int bytesRead) { throw null; }
public override void ImportFromEncryptedPem(System.ReadOnlySpan<char> input, System.ReadOnlySpan<byte> passwordBytes) { }
public override void ImportFromEncryptedPem(System.ReadOnlySpan<char> input, System.ReadOnlySpan<char> password) { }
public override void ImportFromPem(System.ReadOnlySpan<char> input) { }
public virtual void ImportParameters(System.Security.Cryptography.ECParameters parameters) { }
public override void ImportPkcs8PrivateKey(System.ReadOnlySpan<byte> source, out int bytesRead) { throw null; }
public override void ImportSubjectPublicKeyInfo(System.ReadOnlySpan<byte> source, out int bytesRead) { throw null; }
@ -324,6 +330,9 @@ namespace System.Security.Cryptography
public virtual void ImportECPrivateKey(System.ReadOnlySpan<byte> source, out int bytesRead) { throw null; }
public override void ImportEncryptedPkcs8PrivateKey(System.ReadOnlySpan<byte> passwordBytes, System.ReadOnlySpan<byte> source, out int bytesRead) { throw null; }
public override void ImportEncryptedPkcs8PrivateKey(System.ReadOnlySpan<char> password, System.ReadOnlySpan<byte> source, out int bytesRead) { throw null; }
public override void ImportFromEncryptedPem(System.ReadOnlySpan<char> input, System.ReadOnlySpan<byte> passwordBytes) { }
public override void ImportFromEncryptedPem(System.ReadOnlySpan<char> input, System.ReadOnlySpan<char> password) { }
public override void ImportFromPem(System.ReadOnlySpan<char> input) { }
public virtual void ImportParameters(System.Security.Cryptography.ECParameters parameters) { }
public override void ImportPkcs8PrivateKey(System.ReadOnlySpan<byte> source, out int bytesRead) { throw null; }
public override void ImportSubjectPublicKeyInfo(System.ReadOnlySpan<byte> source, out int bytesRead) { throw null; }
@ -573,6 +582,9 @@ namespace System.Security.Cryptography
protected virtual byte[] HashData(System.IO.Stream data, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { throw null; }
public override void ImportEncryptedPkcs8PrivateKey(System.ReadOnlySpan<byte> passwordBytes, System.ReadOnlySpan<byte> source, out int bytesRead) { throw null; }
public override void ImportEncryptedPkcs8PrivateKey(System.ReadOnlySpan<char> password, System.ReadOnlySpan<byte> source, out int bytesRead) { throw null; }
public override void ImportFromEncryptedPem(System.ReadOnlySpan<char> input, System.ReadOnlySpan<byte> passwordBytes) { }
public override void ImportFromEncryptedPem(System.ReadOnlySpan<char> input, System.ReadOnlySpan<char> password) { }
public override void ImportFromPem(System.ReadOnlySpan<char> input) { }
public abstract void ImportParameters(System.Security.Cryptography.RSAParameters parameters);
public override void ImportPkcs8PrivateKey(System.ReadOnlySpan<byte> source, out int bytesRead) { throw null; }
public virtual void ImportRSAPrivateKey(System.ReadOnlySpan<byte> source, out int bytesRead) { throw null; }

View file

@ -81,6 +81,15 @@
<data name="ArgumentNull_Buffer" xml:space="preserve">
<value>Buffer cannot be null.</value>
</data>
<data name="Argument_PemImport_NoPemFound" xml:space="preserve">
<value>No supported key formats were found. Check that the input represents the contents of a PEM-encoded key file, not the path to such a file.</value>
</data>
<data name="Argument_PemImport_AmbiguousPem" xml:space="preserve">
<value>The input contains multiple keys, but only one key can be imported.</value>
</data>
<data name="Argument_PemImport_EncryptedPem" xml:space="preserve">
<value>An encrypted key was found, but no password was provided. Use ImportFromEncryptedPem to import this key.</value>
</data>
<data name="Arg_CryptographyException" xml:space="preserve">
<value>Error occurred during a cryptographic operation.</value>
</data>
@ -320,7 +329,7 @@
</data>
<data name="NotSupported_Method" xml:space="preserve">
<value>Method not supported.</value>
</data>
</data>
<data name="NotSupported_SubclassOverride" xml:space="preserve">
<value>Method not supported. Derived class must override.</value>
</data>

View file

@ -98,6 +98,9 @@
<Compile Include="$(CommonPath)Internal\Cryptography\HashProvider.cs">
<Link>Internal\Cryptography\HashProvider.cs</Link>
</Compile>
<Compile Include="$(CommonPath)Internal\Cryptography\PemKeyImportHelpers.cs">
<Link>Common\Internal\Cryptography\PemKeyImportHelpers.cs</Link>
</Compile>
<Compile Include="$(CommonPath)Internal\Cryptography\UniversalCryptoTransform.cs">
<Link>Internal\Cryptography\UniversalCryptoTransform.cs</Link>
</Compile>
@ -134,6 +137,9 @@
<Compile Include="$(CommonPath)System\Security\Cryptography\PasswordBasedEncryption.cs">
<Link>Common\System\Security\Cryptography\PasswordBasedEncryption.cs</Link>
</Compile>
<Compile Include="$(CommonPath)System\Security\Cryptography\PemLabels.cs">
<Link>Common\System\Security\Cryptography\PemLabels.cs</Link>
</Compile>
<Compile Include="$(CommonPath)System\Security\Cryptography\Pkcs12Kdf.cs">
<Link>Common\System\Security\Cryptography\Pkcs12Kdf.cs</Link>
</Compile>

View file

@ -1125,5 +1125,197 @@ namespace System.Security.Cryptography
throw new ArgumentOutOfRangeException(nameof(signatureFormat));
}
}
/// <summary>
/// Imports an RFC 7468 PEM-encoded key, replacing the keys for this object.
/// </summary>
/// <param name="input">The PEM text of the key to import.</param>
/// <exception cref="ArgumentException">
/// <para>
/// <paramref name="input"/> does not contain a PEM-encoded key with a recognized label.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// <paramref name="input"/> contains multiple PEM-encoded keys with a recognized label.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// <paramref name="input"/> contains an encrypted PEM-encoded key.
/// </para>
/// </exception>
/// <remarks>
/// <para>
/// Unsupported or malformed PEM-encoded objects will be ignored. If multiple supported PEM labels
/// are found, an exception is raised to prevent importing a key when
/// the key is ambiguous.
/// </para>
/// <para>
/// This method supports the following PEM labels:
/// <list type="bullet">
/// <item><description>PUBLIC KEY</description></item>
/// <item><description>PRIVATE KEY</description></item>
/// </list>
/// </para>
/// </remarks>
public override void ImportFromPem(ReadOnlySpan<char> input)
{
PemKeyImportHelpers.ImportPem(input, label => {
if (label.SequenceEqual(PemLabels.Pkcs8PrivateKey))
{
return ImportPkcs8PrivateKey;
}
else if (label.SequenceEqual(PemLabels.SpkiPublicKey))
{
return ImportSubjectPublicKeyInfo;
}
else
{
return null;
}
});
}
/// <summary>
/// Imports an encrypted RFC 7468 PEM-encoded private key, replacing the keys for this object.
/// </summary>
/// <param name="input">The PEM text of the encrypted key to import.</param>
/// <param name="password">
/// The password to use for decrypting the key material.
/// </param>
/// <exception cref="ArgumentException">
/// <para>
/// <paramref name="input"/> does not contain a PEM-encoded key with a recognized label.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// <paramref name="input"/> contains multiple PEM-encoded keys with a recognized label.
/// </para>
/// </exception>
/// <exception cref="CryptographicException">
/// <para>
/// The password is incorrect.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// The base-64 decoded contents of the PEM text from <paramref name="input" />
/// do not represent an ASN.1-BER-encoded PKCS#8 EncryptedPrivateKeyInfo structure.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// The base-64 decoded contents of the PEM text from <paramref name="input" />
/// indicate the key is for an algorithm other than the algorithm
/// represented by this instance.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// The base-64 decoded contents of the PEM text from <paramref name="input" />
/// represent the key in a format that is not supported.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// The algorithm-specific key import failed.
/// </para>
/// </exception>
/// <remarks>
/// <para>
/// When the base-64 decoded contents of <paramref name="input" /> indicate an algorithm that uses PBKDF1
/// (Password-Based Key Derivation Function 1) or PBKDF2 (Password-Based Key Derivation Function 2),
/// the password is converted to bytes via the UTF-8 encoding.
/// </para>
/// <para>
/// Unsupported or malformed PEM-encoded objects will be ignored. If multiple supported PEM labels
/// are found, an exception is thrown to prevent importing a key when
/// the key is ambiguous.
/// </para>
/// <para>This method supports the <c>ENCRYPTED PRIVATE KEY</c> PEM label.</para>
/// </remarks>
public override void ImportFromEncryptedPem(ReadOnlySpan<char> input, ReadOnlySpan<char> password)
{
PemKeyImportHelpers.ImportEncryptedPem<char>(input, password, ImportEncryptedPkcs8PrivateKey);
}
/// <summary>
/// Imports an encrypted RFC 7468 PEM-encoded private key, replacing the keys for this object.
/// </summary>
/// <param name="input">The PEM text of the encrypted key to import.</param>
/// <param name="passwordBytes">
/// The bytes to use as a password when decrypting the key material.
/// </param>
/// <exception cref="ArgumentException">
/// <para>
/// <paramref name="input"/> does not contain a PEM-encoded key with a recognized label.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// <paramref name="input"/> contains multiple PEM-encoded keys with a recognized label.
/// </para>
/// </exception>
/// <exception cref="CryptographicException">
/// <para>
/// The password is incorrect.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// The base-64 decoded contents of the PEM text from <paramref name="input" />
/// do not represent an ASN.1-BER-encoded PKCS#8 EncryptedPrivateKeyInfo structure.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// The base-64 decoded contents of the PEM text from <paramref name="input" />
/// indicate the key is for an algorithm other than the algorithm
/// represented by this instance.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// The base-64 decoded contents of the PEM text from <paramref name="input" />
/// represent the key in a format that is not supported.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// The algorithm-specific key import failed.
/// </para>
/// </exception>
/// <remarks>
/// <para>
/// The password bytes are passed directly into the Key Derivation Function (KDF)
/// used by the algorithm indicated by <c>pbeParameters</c>. This enables compatibility
/// with other systems which use a text encoding other than UTF-8 when processing
/// passwords with PBKDF2 (Password-Based Key Derivation Function 2).
/// </para>
/// <para>
/// Unsupported or malformed PEM-encoded objects will be ignored. If multiple supported PEM labels
/// are found, an exception is thrown to prevent importing a key when
/// the key is ambiguous.
/// </para>
/// <para>This method supports the <c>ENCRYPTED PRIVATE KEY</c> PEM label.</para>
/// </remarks>
public override void ImportFromEncryptedPem(ReadOnlySpan<char> input, ReadOnlySpan<byte> passwordBytes)
{
PemKeyImportHelpers.ImportEncryptedPem<byte>(input, passwordBytes, ImportEncryptedPkcs8PrivateKey);
}
}
}

View file

@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Internal.Cryptography;
using System.Security.Cryptography.Asn1;
namespace System.Security.Cryptography
@ -433,5 +434,202 @@ namespace System.Security.Cryptography
}
}
}
/// <summary>
/// Imports an RFC 7468 PEM-encoded key, replacing the keys for this object.
/// </summary>
/// <param name="input">The PEM text of the key to import.</param>
/// <exception cref="ArgumentException">
/// <para>
/// <paramref name="input"/> does not contain a PEM-encoded key with a recognized label.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// <paramref name="input"/> contains multiple PEM-encoded keys with a recognized label.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// <paramref name="input"/> contains an encrypted PEM-encoded key.
/// </para>
/// </exception>
/// <remarks>
/// <para>
/// Unsupported or malformed PEM-encoded objects will be ignored. If multiple supported PEM labels
/// are found, an exception is raised to prevent importing a key when
/// the key is ambiguous.
/// </para>
/// <para>
/// This method supports the following PEM labels:
/// <list type="bullet">
/// <item><description>PUBLIC KEY</description></item>
/// <item><description>PRIVATE KEY</description></item>
/// <item><description>EC PRIVATE KEY</description></item>
/// </list>
/// </para>
/// </remarks>
public override void ImportFromPem(ReadOnlySpan<char> input)
{
PemKeyImportHelpers.ImportPem(input, label => {
if (label.SequenceEqual(PemLabels.Pkcs8PrivateKey))
{
return ImportPkcs8PrivateKey;
}
else if (label.SequenceEqual(PemLabels.SpkiPublicKey))
{
return ImportSubjectPublicKeyInfo;
}
else if (label.SequenceEqual(PemLabels.EcPrivateKey))
{
return ImportECPrivateKey;
}
else
{
return null;
}
});
}
/// <summary>
/// Imports an encrypted RFC 7468 PEM-encoded private key, replacing the keys for this object.
/// </summary>
/// <param name="input">The PEM text of the encrypted key to import.</param>
/// <param name="password">
/// The password to use for decrypting the key material.
/// </param>
/// <exception cref="ArgumentException">
/// <para>
/// <paramref name="input"/> does not contain a PEM-encoded key with a recognized label.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// <paramref name="input"/> contains multiple PEM-encoded keys with a recognized label.
/// </para>
/// </exception>
/// <exception cref="CryptographicException">
/// <para>
/// The password is incorrect.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// The base-64 decoded contents of the PEM text from <paramref name="input" />
/// do not represent an ASN.1-BER-encoded PKCS#8 EncryptedPrivateKeyInfo structure.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// The base-64 decoded contents of the PEM text from <paramref name="input" />
/// indicate the key is for an algorithm other than the algorithm
/// represented by this instance.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// The base-64 decoded contents of the PEM text from <paramref name="input" />
/// represent the key in a format that is not supported.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// The algorithm-specific key import failed.
/// </para>
/// </exception>
/// <remarks>
/// <para>
/// When the base-64 decoded contents of <paramref name="input" /> indicate an algorithm that uses PBKDF1
/// (Password-Based Key Derivation Function 1) or PBKDF2 (Password-Based Key Derivation Function 2),
/// the password is converted to bytes via the UTF-8 encoding.
/// </para>
/// <para>
/// Unsupported or malformed PEM-encoded objects will be ignored. If multiple supported PEM labels
/// are found, an exception is thrown to prevent importing a key when
/// the key is ambiguous.
/// </para>
/// <para>This method supports the <c>ENCRYPTED PRIVATE KEY</c> PEM label.</para>
/// </remarks>
public override void ImportFromEncryptedPem(ReadOnlySpan<char> input, ReadOnlySpan<char> password)
{
PemKeyImportHelpers.ImportEncryptedPem<char>(input, password, ImportEncryptedPkcs8PrivateKey);
}
/// <summary>
/// Imports an encrypted RFC 7468 PEM-encoded private key, replacing the keys for this object.
/// </summary>
/// <param name="input">The PEM text of the encrypted key to import.</param>
/// <param name="passwordBytes">
/// The bytes to use as a password when decrypting the key material.
/// </param>
/// <exception cref="ArgumentException">
/// <para>
/// <paramref name="input"/> does not contain a PEM-encoded key with a recognized label.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// <paramref name="input"/> contains multiple PEM-encoded keys with a recognized label.
/// </para>
/// </exception>
/// <exception cref="CryptographicException">
/// <para>
/// The password is incorrect.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// The base-64 decoded contents of the PEM text from <paramref name="input" />
/// do not represent an ASN.1-BER-encoded PKCS#8 EncryptedPrivateKeyInfo structure.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// The base-64 decoded contents of the PEM text from <paramref name="input" />
/// indicate the key is for an algorithm other than the algorithm
/// represented by this instance.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// The base-64 decoded contents of the PEM text from <paramref name="input" />
/// represent the key in a format that is not supported.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// The algorithm-specific key import failed.
/// </para>
/// </exception>
/// <remarks>
/// <para>
/// The password bytes are passed directly into the Key Derivation Function (KDF)
/// used by the algorithm indicated by <c>pbeParameters</c>. This enables compatibility
/// with other systems which use a text encoding other than UTF-8 when processing
/// passwords with PBKDF2 (Password-Based Key Derivation Function 2).
/// </para>
/// <para>
/// Unsupported or malformed PEM-encoded objects will be ignored. If multiple supported PEM labels
/// are found, an exception is thrown to prevent importing a key when
/// the key is ambiguous.
/// </para>
/// <para>This method supports the <c>ENCRYPTED PRIVATE KEY</c> PEM label.</para>
/// </remarks>
public override void ImportFromEncryptedPem(ReadOnlySpan<char> input, ReadOnlySpan<byte> passwordBytes)
{
PemKeyImportHelpers.ImportEncryptedPem<byte>(input, passwordBytes, ImportEncryptedPkcs8PrivateKey);
}
}
}

View file

@ -1298,5 +1298,202 @@ namespace System.Security.Cryptography
throw new ArgumentOutOfRangeException(nameof(signatureFormat));
}
}
/// <summary>
/// Imports an RFC 7468 PEM-encoded key, replacing the keys for this object.
/// </summary>
/// <param name="input">The PEM text of the key to import.</param>
/// <exception cref="ArgumentException">
/// <para>
/// <paramref name="input"/> does not contain a PEM-encoded key with a recognized label.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// <paramref name="input"/> contains multiple PEM-encoded keys with a recognized label.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// <paramref name="input"/> contains an encrypted PEM-encoded key.
/// </para>
/// </exception>
/// <remarks>
/// <para>
/// Unsupported or malformed PEM-encoded objects will be ignored. If multiple supported PEM labels
/// are found, an exception is raised to prevent importing a key when
/// the key is ambiguous.
/// </para>
/// <para>
/// This method supports the following PEM labels:
/// <list type="bullet">
/// <item><description>PUBLIC KEY</description></item>
/// <item><description>PRIVATE KEY</description></item>
/// <item><description>EC PRIVATE KEY</description></item>
/// </list>
/// </para>
/// </remarks>
public override void ImportFromPem(ReadOnlySpan<char> input)
{
PemKeyImportHelpers.ImportPem(input, label => {
if (label.SequenceEqual(PemLabels.Pkcs8PrivateKey))
{
return ImportPkcs8PrivateKey;
}
else if (label.SequenceEqual(PemLabels.SpkiPublicKey))
{
return ImportSubjectPublicKeyInfo;
}
else if (label.SequenceEqual(PemLabels.EcPrivateKey))
{
return ImportECPrivateKey;
}
else
{
return null;
}
});
}
/// <summary>
/// Imports an encrypted RFC 7468 PEM-encoded private key, replacing the keys for this object.
/// </summary>
/// <param name="input">The PEM text of the encrypted key to import.</param>
/// <param name="password">
/// The password to use for decrypting the key material.
/// </param>
/// <exception cref="ArgumentException">
/// <para>
/// <paramref name="input"/> does not contain a PEM-encoded key with a recognized label.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// <paramref name="input"/> contains multiple PEM-encoded keys with a recognized label.
/// </para>
/// </exception>
/// <exception cref="CryptographicException">
/// <para>
/// The password is incorrect.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// The base-64 decoded contents of the PEM text from <paramref name="input" />
/// do not represent an ASN.1-BER-encoded PKCS#8 EncryptedPrivateKeyInfo structure.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// The base-64 decoded contents of the PEM text from <paramref name="input" />
/// indicate the key is for an algorithm other than the algorithm
/// represented by this instance.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// The base-64 decoded contents of the PEM text from <paramref name="input" />
/// represent the key in a format that is not supported.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// The algorithm-specific key import failed.
/// </para>
/// </exception>
/// <remarks>
/// <para>
/// When the base-64 decoded contents of <paramref name="input" /> indicate an algorithm that uses PBKDF1
/// (Password-Based Key Derivation Function 1) or PBKDF2 (Password-Based Key Derivation Function 2),
/// the password is converted to bytes via the UTF-8 encoding.
/// </para>
/// <para>
/// Unsupported or malformed PEM-encoded objects will be ignored. If multiple supported PEM labels
/// are found, an exception is thrown to prevent importing a key when
/// the key is ambiguous.
/// </para>
/// <para>This method supports the <c>ENCRYPTED PRIVATE KEY</c> PEM label.</para>
/// </remarks>
public override void ImportFromEncryptedPem(ReadOnlySpan<char> input, ReadOnlySpan<char> password)
{
PemKeyImportHelpers.ImportEncryptedPem<char>(input, password, ImportEncryptedPkcs8PrivateKey);
}
/// <summary>
/// Imports an encrypted RFC 7468 PEM-encoded private key, replacing the keys for this object.
/// </summary>
/// <param name="input">The PEM text of the encrypted key to import.</param>
/// <param name="passwordBytes">
/// The bytes to use as a password when decrypting the key material.
/// </param>
/// <exception cref="ArgumentException">
/// <para>
/// <paramref name="input"/> does not contain a PEM-encoded key with a recognized label.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// <paramref name="input"/> contains multiple PEM-encoded keys with a recognized label.
/// </para>
/// </exception>
/// <exception cref="CryptographicException">
/// <para>
/// The password is incorrect.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// The base-64 decoded contents of the PEM text from <paramref name="input" />
/// do not represent an ASN.1-BER-encoded PKCS#8 EncryptedPrivateKeyInfo structure.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// The base-64 decoded contents of the PEM text from <paramref name="input" />
/// indicate the key is for an algorithm other than the algorithm
/// represented by this instance.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// The base-64 decoded contents of the PEM text from <paramref name="input" />
/// represent the key in a format that is not supported.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// The algorithm-specific key import failed.
/// </para>
/// </exception>
/// <remarks>
/// <para>
/// The password bytes are passed directly into the Key Derivation Function (KDF)
/// used by the algorithm indicated by <c>pbeParameters</c>. This enables compatibility
/// with other systems which use a text encoding other than UTF-8 when processing
/// passwords with PBKDF2 (Password-Based Key Derivation Function 2).
/// </para>
/// <para>
/// Unsupported or malformed PEM-encoded objects will be ignored. If multiple supported PEM labels
/// are found, an exception is thrown to prevent importing a key when
/// the key is ambiguous.
/// </para>
/// <para>This method supports the <c>ENCRYPTED PRIVATE KEY</c> PEM label.</para>
/// </remarks>
public override void ImportFromEncryptedPem(ReadOnlySpan<char> input, ReadOnlySpan<byte> passwordBytes)
{
PemKeyImportHelpers.ImportEncryptedPem<byte>(input, passwordBytes, ImportEncryptedPkcs8PrivateKey);
}
}
}

View file

@ -625,6 +625,208 @@ namespace System.Security.Cryptography
bytesRead = localRead;
}
/// <summary>
/// Imports an RFC 7468 PEM-encoded key, replacing the keys for this object.
/// </summary>
/// <param name="input">The PEM text of the key to import.</param>
/// <exception cref="ArgumentException">
/// <para>
/// <paramref name="input"/> does not contain a PEM-encoded key with a recognized label.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// <paramref name="input"/> contains multiple PEM-encoded keys with a recognized label.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// <paramref name="input"/> contains an encrypted PEM-encoded key.
/// </para>
/// </exception>
/// <remarks>
/// <para>
/// Unsupported or malformed PEM-encoded objects will be ignored. If multiple supported PEM labels
/// are found, an exception is raised to prevent importing a key when
/// the key is ambiguous.
/// </para>
/// <para>
/// This method supports the following PEM labels:
/// <list type="bullet">
/// <item><description>PUBLIC KEY</description></item>
/// <item><description>PRIVATE KEY</description></item>
/// <item><description>RSA PRIVATE KEY</description></item>
/// <item><description>RSA PUBLIC KEY</description></item>
/// </list>
/// </para>
/// </remarks>
public override void ImportFromPem(ReadOnlySpan<char> input)
{
PemKeyImportHelpers.ImportPem(input, label => {
if (label.SequenceEqual(PemLabels.RsaPrivateKey))
{
return ImportRSAPrivateKey;
}
else if (label.SequenceEqual(PemLabels.Pkcs8PrivateKey))
{
return ImportPkcs8PrivateKey;
}
else if (label.SequenceEqual(PemLabels.RsaPublicKey))
{
return ImportRSAPublicKey;
}
else if (label.SequenceEqual(PemLabels.SpkiPublicKey))
{
return ImportSubjectPublicKeyInfo;
}
else
{
return null;
}
});
}
/// <summary>
/// Imports an encrypted RFC 7468 PEM-encoded private key, replacing the keys for this object.
/// </summary>
/// <param name="input">The PEM text of the encrypted key to import.</param>
/// <param name="password">
/// The password to use for decrypting the key material.
/// </param>
/// <exception cref="ArgumentException">
/// <para>
/// <paramref name="input"/> does not contain a PEM-encoded key with a recognized label.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// <paramref name="input"/> contains multiple PEM-encoded keys with a recognized label.
/// </para>
/// </exception>
/// <exception cref="CryptographicException">
/// <para>
/// The password is incorrect.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// The base-64 decoded contents of the PEM text from <paramref name="input" />
/// do not represent an ASN.1-BER-encoded PKCS#8 EncryptedPrivateKeyInfo structure.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// The base-64 decoded contents of the PEM text from <paramref name="input" />
/// indicate the key is for an algorithm other than the algorithm
/// represented by this instance.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// The base-64 decoded contents of the PEM text from <paramref name="input" />
/// represent the key in a format that is not supported.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// The algorithm-specific key import failed.
/// </para>
/// </exception>
/// <remarks>
/// <para>
/// When the base-64 decoded contents of <paramref name="input" /> indicate an algorithm that uses PBKDF1
/// (Password-Based Key Derivation Function 1) or PBKDF2 (Password-Based Key Derivation Function 2),
/// the password is converted to bytes via the UTF-8 encoding.
/// </para>
/// <para>
/// Unsupported or malformed PEM-encoded objects will be ignored. If multiple supported PEM labels
/// are found, an exception is thrown to prevent importing a key when
/// the key is ambiguous.
/// </para>
/// <para>This method supports the <c>ENCRYPTED PRIVATE KEY</c> PEM label.</para>
/// </remarks>
public override void ImportFromEncryptedPem(ReadOnlySpan<char> input, ReadOnlySpan<char> password)
{
PemKeyImportHelpers.ImportEncryptedPem<char>(input, password, ImportEncryptedPkcs8PrivateKey);
}
/// <summary>
/// Imports an encrypted RFC 7468 PEM-encoded private key, replacing the keys for this object.
/// </summary>
/// <param name="input">The PEM text of the encrypted key to import.</param>
/// <param name="passwordBytes">
/// The bytes to use as a password when decrypting the key material.
/// </param>
/// <exception cref="ArgumentException">
/// <para>
/// <paramref name="input"/> does not contain a PEM-encoded key with a recognized label.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// <paramref name="input"/> contains multiple PEM-encoded keys with a recognized label.
/// </para>
/// </exception>
/// <exception cref="CryptographicException">
/// <para>
/// The password is incorrect.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// The base-64 decoded contents of the PEM text from <paramref name="input" />
/// do not represent an ASN.1-BER-encoded PKCS#8 EncryptedPrivateKeyInfo structure.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// The base-64 decoded contents of the PEM text from <paramref name="input" />
/// indicate the key is for an algorithm other than the algorithm
/// represented by this instance.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// The base-64 decoded contents of the PEM text from <paramref name="input" />
/// represent the key in a format that is not supported.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// The algorithm-specific key import failed.
/// </para>
/// </exception>
/// <remarks>
/// <para>
/// The password bytes are passed directly into the Key Derivation Function (KDF)
/// used by the algorithm indicated by <c>pbeParameters</c>. This enables compatibility
/// with other systems which use a text encoding other than UTF-8 when processing
/// passwords with PBKDF2 (Password-Based Key Derivation Function 2).
/// </para>
/// <para>
/// Unsupported or malformed PEM-encoded objects will be ignored. If multiple supported PEM labels
/// are found, an exception is thrown to prevent importing a key when
/// the key is ambiguous.
/// </para>
/// <para>This method supports the <c>ENCRYPTED PRIVATE KEY</c> PEM label.</para>
/// </remarks>
public override void ImportFromEncryptedPem(ReadOnlySpan<char> input, ReadOnlySpan<byte> passwordBytes)
{
PemKeyImportHelpers.ImportEncryptedPem<byte>(input, passwordBytes, ImportEncryptedPkcs8PrivateKey);
}
private static void ClearPrivateParameters(in RSAParameters rsaParameters)
{
CryptographicOperations.ZeroMemory(rsaParameters.D);

View file

@ -141,15 +141,24 @@
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\DSA\DSAKeyFileTests.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSAKeyFileTests.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\DSA\DSAKeyPemTests.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSAKeyPemTests.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\EC\ECKeyFileTests.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\EC\ECKeyFileTests.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\EC\ECKeyFileTests.LimitedPrivate.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\EC\ECKeyFileTests.LimitedPrivate.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\EC\ECKeyPemTests.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\EC\ECKeyPemTests.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDhKeyFileTests.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDhKeyFileTests.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanKeyPemTests.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanKeyPemTests.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanFactory.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanFactory.cs</Link>
</Compile>
@ -177,9 +186,15 @@
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaKeyFileTests.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaKeyFileTests.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaKeyPemTests.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaKeyPemTests.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\RSA\RSAKeyFileTests.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\RSAKeyFileTests.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\RSA\RSAKeyPemTests.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\RSAKeyPemTests.cs</Link>
</Compile>
<Compile Include="AesManagedTests.cs" />
<Compile Include="AsymmetricSignatureFormatterTests.cs" />
<Compile Include="BlockSizeValueTests.cs" />
@ -283,4 +298,4 @@
<Compile Include="AesGcmTests.cs" />
<Compile Include="HKDFTests.cs" />
</ItemGroup>
</Project>
</Project>

View file

@ -117,6 +117,9 @@
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\DSA\DSAKeyFileTests.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSAKeyFileTests.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\DSA\DSAKeyPemTests.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSAKeyPemTests.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\DSA\DSASignatureFormatter.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSASignatureFormatter.cs</Link>
</Compile>
@ -138,15 +141,24 @@
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\EC\ECKeyFileTests.LimitedPrivate.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\EC\ECKeyFileTests.LimitedPrivate.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\EC\ECKeyPemTests.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\EC\ECKeyPemTests.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDhKeyFileTests.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDhKeyFileTests.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanKeyPemTests.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanKeyPemTests.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaTests.netcoreapp.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaTests.netcoreapp.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaKeyFileTests.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaKeyFileTests.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaKeyPemTests.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaKeyPemTests.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaSignatureFormatTests.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaSignatureFormatTests.cs</Link>
</Compile>
@ -162,6 +174,9 @@
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\RSA\RSAKeyFileTests.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\RSAKeyFileTests.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\RSA\RSAKeyPemTests.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\RSAKeyPemTests.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\RSA\RSASignatureFormatter.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\RSASignatureFormatter.cs</Link>
</Compile>

View file

@ -51,6 +51,9 @@ namespace System.Security.Cryptography.Csp.Tests
// DecryptValue and EncryptValue throw PNSE in base class, so they don't need to be checked.
"DecryptValue",
"EncryptValue",
// PEM Import/Export defers to Import methods.
"ImportFromPem",
"ImportFromEncryptedPem",
// Key Import/Export defers to ImportParameters/ExportParameters (covered by *KeyFileTests)
"ImportRSAPrivateKey",
"ImportRSAPublicKey",

View file

@ -75,6 +75,9 @@
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\DSA\DSAKeyFileTests.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSAKeyFileTests.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\DSA\DSAKeyPemTests.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSAKeyPemTests.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\DSA\DSAKeyGeneration.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSAKeyGeneration.cs</Link>
</Compile>
@ -117,6 +120,9 @@
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\RSA\RSAKeyFileTests.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\RSAKeyFileTests.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\RSA\RSAKeyPemTests.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\RSAKeyPemTests.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\RSA\SignVerify.netcoreapp.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\SignVerify.netcoreapp.cs</Link>
</Compile>

View file

@ -140,18 +140,30 @@
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\DSA\DSAKeyFileTests.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSAKeyFileTests.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\DSA\DSAKeyPemTests.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSAKeyPemTests.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\EC\ECKeyFileTests.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\EC\ECKeyFileTests.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\EC\ECKeyFileTests.LimitedPrivate.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\EC\ECKeyFileTests.LimitedPrivate.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\EC\ECKeyPemTests.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\EC\ECKeyPemTests.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDhKeyFileTests.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDhKeyFileTests.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanKeyPemTests.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanKeyPemTests.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaKeyFileTests.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaKeyFileTests.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaKeyPemTests.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaKeyPemTests.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaTests.netcoreapp.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaTests.netcoreapp.cs</Link>
</Compile>
@ -161,9 +173,12 @@
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\RSA\RSAKeyFileTests.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\RSAKeyFileTests.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\RSA\RSAKeyPemTests.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\RSAKeyPemTests.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\RSA\SignVerify.netcoreapp.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\SignVerify.netcoreapp.cs</Link>
</Compile>
<Compile Include="SafeEvpPKeyHandleTests.cs" />
</ItemGroup>
</Project>
</Project>

View file

@ -28,6 +28,9 @@ namespace System.Security.Cryptography
public virtual void FromXmlString(string xmlString) { }
public virtual void ImportEncryptedPkcs8PrivateKey(System.ReadOnlySpan<byte> passwordBytes, System.ReadOnlySpan<byte> source, out int bytesRead) { throw null; }
public virtual void ImportEncryptedPkcs8PrivateKey(System.ReadOnlySpan<char> password, System.ReadOnlySpan<byte> source, out int bytesRead) { throw null; }
public virtual void ImportFromEncryptedPem(System.ReadOnlySpan<char> input, System.ReadOnlySpan<byte> passwordBytes) { }
public virtual void ImportFromEncryptedPem(System.ReadOnlySpan<char> input, System.ReadOnlySpan<char> password) { }
public virtual void ImportFromPem(System.ReadOnlySpan<char> input) { }
public virtual void ImportPkcs8PrivateKey(System.ReadOnlySpan<byte> source, out int bytesRead) { throw null; }
public virtual void ImportSubjectPublicKeyInfo(System.ReadOnlySpan<byte> source, out int bytesRead) { throw null; }
public virtual string ToXmlString(bool includePrivateParameters) { throw null; }

View file

@ -164,6 +164,57 @@ namespace System.Security.Cryptography
public virtual bool TryExportSubjectPublicKeyInfo(Span<byte> destination, out int bytesWritten) =>
throw new NotImplementedException(SR.NotSupported_SubclassOverride);
/// <summary>
/// When overridden in a derived class, imports an encrypted RFC 7468
/// PEM-encoded key, replacing the keys for this object.
/// </summary>
/// <param name="input">The PEM text of the encrypted key to import.</param>
/// <param name="password">
/// The password to use for decrypting the key material.
/// </param>
/// <exception cref="NotImplementedException">
/// A derived type has not overridden this member.
/// </exception>
/// <remarks>
/// Because each algorithm may have algorithm-specific PEM labels, the
/// default behavior will throw <see cref="NotImplementedException" />.
/// </remarks>
public virtual void ImportFromEncryptedPem(ReadOnlySpan<char> input, ReadOnlySpan<char> password) =>
throw new NotImplementedException(SR.NotSupported_SubclassOverride);
/// <summary>
/// When overridden in a derived class, imports an encrypted RFC 7468
/// PEM-encoded key, replacing the keys for this object.
/// </summary>
/// <param name="input">The PEM text of the encrypted key to import.</param>
/// <param name="passwordBytes">
/// The bytes to use as a password when decrypting the key material.
/// </param>
/// <exception cref="NotImplementedException">
/// A derived type has not overridden this member.
/// </exception>
/// <remarks>
/// Because each algorithm may have algorithm-specific PEM labels, the
/// default behavior will throw <see cref="NotImplementedException" />.
/// </remarks>
public virtual void ImportFromEncryptedPem(ReadOnlySpan<char> input, ReadOnlySpan<byte> passwordBytes) =>
throw new NotImplementedException(SR.NotSupported_SubclassOverride);
/// <summary>
/// When overridden in a derived class, imports an RFC 7468 textually
/// encoded key, replacing the keys for this object.
/// </summary>
/// <param name="input">The text of the PEM key to import.</param>
/// <exception cref="NotImplementedException">
/// A derived type has not overridden this member.
/// </exception>
/// <remarks>
/// Because each algorithm may have algorithm-specific PEM labels, the
/// default behavior will throw <see cref="NotImplementedException" />.
/// </remarks>
public virtual void ImportFromPem(ReadOnlySpan<char> input) =>
throw new NotImplementedException(SR.NotSupported_SubclassOverride);
private delegate bool TryExportPbe<T>(
ReadOnlySpan<T> password,
PbeParameters pbeParameters,