From d39d805951d58e786ec08488b7f5d52fdb2a80f1 Mon Sep 17 00:00:00 2001 From: Kevin Jones Date: Tue, 9 Nov 2021 03:04:25 -0500 Subject: [PATCH] Provide PEM implementations for AsymmetricAlgorithm. Now that the Encoding and Primitive assemblies are unified, an implementation for PKCS#8 and SPKI keys can be provided in the abstract AsymmetricAlgorithm. Derived types will continue to override these members to provide support for additional PEM labels. --- .../src/System/Security/Cryptography/DSA.cs | 25 +- .../Security/Cryptography/ECDiffieHellman.cs | 8 +- .../src/System/Security/Cryptography/ECDsa.cs | 8 +- .../src/System/Security/Cryptography/RSA.cs | 8 +- .../src/Resources/Strings.resx | 9 + .../src/System.Security.Cryptography.csproj | 4 + .../Cryptography/AsymmetricAlgorithm.cs | 206 ++++++++++++-- .../tests/AsymmetricAlgorithmTests.cs | 257 ++++++++++++++++++ .../System.Security.Cryptography.Tests.csproj | 1 + 9 files changed, 483 insertions(+), 43 deletions(-) create mode 100644 src/libraries/System.Security.Cryptography/tests/AsymmetricAlgorithmTests.cs diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/DSA.cs b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/DSA.cs index 1d28e7681b09b..d9c8944f530f9 100644 --- a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/DSA.cs +++ b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/DSA.cs @@ -1173,20 +1173,9 @@ public int GetMaxSignatureSize(DSASignatureFormat signatureFormat) /// public override void ImportFromPem(ReadOnlySpan input) { - PemKeyImportHelpers.ImportPem(input, label => { - if (label.SequenceEqual(PemLabels.Pkcs8PrivateKey)) - { - return ImportPkcs8PrivateKey; - } - else if (label.SequenceEqual(PemLabels.SpkiPublicKey)) - { - return ImportSubjectPublicKeyInfo; - } - else - { - return null; - } - }); + // Implementation has been pushed down to AsymmetricAlgorithm. The + // override remains for compatibility. + base.ImportFromPem(input); } /// @@ -1255,7 +1244,9 @@ public override void ImportFromPem(ReadOnlySpan input) /// public override void ImportFromEncryptedPem(ReadOnlySpan input, ReadOnlySpan password) { - PemKeyImportHelpers.ImportEncryptedPem(input, password, ImportEncryptedPkcs8PrivateKey); + // Implementation has been pushed down to AsymmetricAlgorithm. The + // override remains for compatibility. + base.ImportFromEncryptedPem(input, password); } /// @@ -1325,7 +1316,9 @@ public override void ImportFromEncryptedPem(ReadOnlySpan input, ReadOnlySp /// public override void ImportFromEncryptedPem(ReadOnlySpan input, ReadOnlySpan passwordBytes) { - PemKeyImportHelpers.ImportEncryptedPem(input, passwordBytes, ImportEncryptedPkcs8PrivateKey); + // Implementation has been pushed down to AsymmetricAlgorithm. The + // override remains for compatibility. + base.ImportFromEncryptedPem(input, passwordBytes); } } } diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellman.cs b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellman.cs index a1661ab9ed701..bb81dab7bfe3f 100644 --- a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellman.cs +++ b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellman.cs @@ -555,7 +555,9 @@ public override void ImportFromPem(ReadOnlySpan input) /// public override void ImportFromEncryptedPem(ReadOnlySpan input, ReadOnlySpan password) { - PemKeyImportHelpers.ImportEncryptedPem(input, password, ImportEncryptedPkcs8PrivateKey); + // Implementation has been pushed down to AsymmetricAlgorithm. The + // override remains for compatibility. + base.ImportFromEncryptedPem(input, password); } /// @@ -625,7 +627,9 @@ public override void ImportFromEncryptedPem(ReadOnlySpan input, ReadOnlySp /// public override void ImportFromEncryptedPem(ReadOnlySpan input, ReadOnlySpan passwordBytes) { - PemKeyImportHelpers.ImportEncryptedPem(input, passwordBytes, ImportEncryptedPkcs8PrivateKey); + // Implementation has been pushed down to AsymmetricAlgorithm. The + // override remains for compatibility. + base.ImportFromEncryptedPem(input, passwordBytes); } } } diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDsa.cs b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDsa.cs index 4b46ecc95f697..4c6d1cc38c219 100644 --- a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDsa.cs +++ b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDsa.cs @@ -1419,7 +1419,9 @@ public override void ImportFromPem(ReadOnlySpan input) /// public override void ImportFromEncryptedPem(ReadOnlySpan input, ReadOnlySpan password) { - PemKeyImportHelpers.ImportEncryptedPem(input, password, ImportEncryptedPkcs8PrivateKey); + // Implementation has been pushed down to AsymmetricAlgorithm. The + // override remains for compatibility. + base.ImportFromEncryptedPem(input, password); } /// @@ -1489,7 +1491,9 @@ public override void ImportFromEncryptedPem(ReadOnlySpan input, ReadOnlySp /// public override void ImportFromEncryptedPem(ReadOnlySpan input, ReadOnlySpan passwordBytes) { - PemKeyImportHelpers.ImportEncryptedPem(input, passwordBytes, ImportEncryptedPkcs8PrivateKey); + // Implementation has been pushed down to AsymmetricAlgorithm. The + // override remains for compatibility. + base.ImportFromEncryptedPem(input, passwordBytes); } } } diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/RSA.cs b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/RSA.cs index 2d0919e2f1cd5..d98396703ee62 100644 --- a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/RSA.cs +++ b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/RSA.cs @@ -769,7 +769,9 @@ public override void ImportFromPem(ReadOnlySpan input) /// public override void ImportFromEncryptedPem(ReadOnlySpan input, ReadOnlySpan password) { - PemKeyImportHelpers.ImportEncryptedPem(input, password, ImportEncryptedPkcs8PrivateKey); + // Implementation has been pushed down to AsymmetricAlgorithm. The + // override remains for compatibility. + base.ImportFromEncryptedPem(input, password); } /// @@ -839,7 +841,9 @@ public override void ImportFromEncryptedPem(ReadOnlySpan input, ReadOnlySp /// public override void ImportFromEncryptedPem(ReadOnlySpan input, ReadOnlySpan passwordBytes) { - PemKeyImportHelpers.ImportEncryptedPem(input, passwordBytes, ImportEncryptedPkcs8PrivateKey); + // Implementation has been pushed down to AsymmetricAlgorithm. The + // override remains for compatibility. + base.ImportFromEncryptedPem(input, passwordBytes); } private static void ClearPrivateParameters(in RSAParameters rsaParameters) diff --git a/src/libraries/System.Security.Cryptography/src/Resources/Strings.resx b/src/libraries/System.Security.Cryptography/src/Resources/Strings.resx index 043b8dff0ae18..5473ef0b799f6 100644 --- a/src/libraries/System.Security.Cryptography/src/Resources/Strings.resx +++ b/src/libraries/System.Security.Cryptography/src/Resources/Strings.resx @@ -90,6 +90,15 @@ The encoded PEM size is too large to represent as a signed 32-bit integer. + + 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. + + + The input contains multiple keys, but only one key can be imported. + + + An encrypted key was found, but no password was provided. Use ImportFromEncryptedPem to import this key. + Index was out of range. Must be non-negative and less than the size of the collection. diff --git a/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj b/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj index 37059f8f67e8b..091ebeec2de2b 100644 --- a/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj +++ b/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj @@ -21,12 +21,16 @@ Link="Common\System\Obsoletions.cs" /> + + diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AsymmetricAlgorithm.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AsymmetricAlgorithm.cs index 48142e3152874..840824add2dbc 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AsymmetricAlgorithm.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AsymmetricAlgorithm.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Internal.Cryptography; using System.Diagnostics.CodeAnalysis; namespace System.Security.Cryptography @@ -165,55 +166,218 @@ public virtual bool TryExportSubjectPublicKeyInfo(Span destination, out in throw new NotImplementedException(SR.NotSupported_SubclassOverride); /// - /// When overridden in a derived class, imports an encrypted RFC 7468 - /// PEM-encoded key, replacing the keys for this object. + /// Imports an encrypted RFC 7468 PEM-encoded key, replacing the keys for this object. /// /// The PEM text of the encrypted key to import. /// /// The password to use for decrypting the key material. /// + /// + /// + /// does not contain a PEM-encoded key with a recognized label. + /// + /// + /// -or- + /// + /// + /// contains multiple PEM-encoded keys with a recognized label. + /// + /// + /// + /// + /// The password is incorrect. + /// + /// + /// -or- + /// + /// + /// The base-64 decoded contents of the PEM text from + /// do not represent an ASN.1-BER-encoded PKCS#8 EncryptedPrivateKeyInfo structure. + /// + /// + /// -or- + /// + /// + /// The base-64 decoded contents of the PEM text from + /// indicate the key is for an algorithm other than the algorithm + /// represented by this instance. + /// + /// + /// -or- + /// + /// + /// The base-64 decoded contents of the PEM text from + /// represent the key in a format that is not supported. + /// + /// + /// -or- + /// + /// + /// The algorithm-specific key import failed. + /// + /// /// - /// A derived type has not overridden this member. + /// A derived type has not provided an implementation for + /// . /// /// - /// Because each algorithm may have algorithm-specific PEM labels, the - /// default behavior will throw . + /// + /// When the base-64 decoded contents of 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. + /// + /// + /// 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. + /// + /// This method supports the ENCRYPTED PRIVATE KEY PEM label. + /// + /// Types that override this method may support additional PEM labels. + /// /// - public virtual void ImportFromEncryptedPem(ReadOnlySpan input, ReadOnlySpan password) => - throw new NotImplementedException(SR.NotSupported_SubclassOverride); + public virtual void ImportFromEncryptedPem(ReadOnlySpan input, ReadOnlySpan password) + { + PemKeyImportHelpers.ImportEncryptedPem(input, password, ImportEncryptedPkcs8PrivateKey); + } /// - /// When overridden in a derived class, imports an encrypted RFC 7468 - /// PEM-encoded key, replacing the keys for this object. + /// Imports an encrypted RFC 7468 PEM-encoded key, replacing the keys for this object. /// /// The PEM text of the encrypted key to import. /// /// The bytes to use as a password when decrypting the key material. /// + /// + /// + /// does not contain a PEM-encoded key with a recognized label. + /// + /// + /// -or- + /// + /// + /// contains multiple PEM-encoded keys with a recognized label. + /// + /// + /// + /// + /// The password is incorrect. + /// + /// + /// -or- + /// + /// + /// The base-64 decoded contents of the PEM text from + /// do not represent an ASN.1-BER-encoded PKCS#8 EncryptedPrivateKeyInfo structure. + /// + /// + /// -or- + /// + /// + /// The base-64 decoded contents of the PEM text from + /// indicate the key is for an algorithm other than the algorithm + /// represented by this instance. + /// + /// + /// -or- + /// + /// + /// The base-64 decoded contents of the PEM text from + /// represent the key in a format that is not supported. + /// + /// + /// -or- + /// + /// + /// The algorithm-specific key import failed. + /// + /// /// - /// A derived type has not overridden this member. + /// A derived type has not provided an implementation for + /// . /// /// - /// Because each algorithm may have algorithm-specific PEM labels, the - /// default behavior will throw . + /// + /// The password bytes are passed directly into the Key Derivation Function (KDF) + /// used by the algorithm indicated by pbeParameters. 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). + /// + /// + /// 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. + /// + /// This method supports the ENCRYPTED PRIVATE KEY PEM label. + /// + /// Types that override this method may support additional PEM labels. + /// /// - public virtual void ImportFromEncryptedPem(ReadOnlySpan input, ReadOnlySpan passwordBytes) => - throw new NotImplementedException(SR.NotSupported_SubclassOverride); + public virtual void ImportFromEncryptedPem(ReadOnlySpan input, ReadOnlySpan passwordBytes) + { + PemKeyImportHelpers.ImportEncryptedPem(input, passwordBytes, ImportEncryptedPkcs8PrivateKey); + } /// - /// When overridden in a derived class, imports an RFC 7468 textually - /// encoded key, replacing the keys for this object. + /// Imports an RFC 7468 textually encoded key, replacing the keys for this object. /// /// The text of the PEM key to import. + /// + /// + /// does not contain a PEM-encoded key with a recognized label. + /// + /// + /// -or- + /// + /// + /// contains multiple PEM-encoded keys with a recognized label. + /// + /// + /// -or- + /// + /// + /// contains an encrypted PEM-encoded key. + /// + /// /// - /// A derived type has not overridden this member. + /// A derived type has not provided an implementation for + /// or . /// /// - /// Because each algorithm may have algorithm-specific PEM labels, the - /// default behavior will throw . + /// + /// 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. + /// + /// + /// This method supports the following PEM labels: + /// + /// PUBLIC KEY + /// PRIVATE KEY + /// + /// + /// + /// Types that override this method may support additional PEM labels. + /// /// - public virtual void ImportFromPem(ReadOnlySpan input) => - throw new NotImplementedException(SR.NotSupported_SubclassOverride); + public virtual void ImportFromPem(ReadOnlySpan input) + { + PemKeyImportHelpers.ImportPem(input, label => + { + if (label.SequenceEqual(PemLabels.Pkcs8PrivateKey)) + { + return ImportPkcs8PrivateKey; + } + else if (label.SequenceEqual(PemLabels.SpkiPublicKey)) + { + return ImportSubjectPublicKeyInfo; + } + else + { + return null; + } + }); + } private delegate bool TryExportPbe( ReadOnlySpan password, diff --git a/src/libraries/System.Security.Cryptography/tests/AsymmetricAlgorithmTests.cs b/src/libraries/System.Security.Cryptography/tests/AsymmetricAlgorithmTests.cs new file mode 100644 index 0000000000000..4e2165d2534ba --- /dev/null +++ b/src/libraries/System.Security.Cryptography/tests/AsymmetricAlgorithmTests.cs @@ -0,0 +1,257 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Xunit; + +namespace System.Security.Cryptography.Tests +{ + public static class AsymmetricAlgorithmTests + { + [Fact] + public static void ImportFromPem_AcceptsSubjectPublicKeyInfo() + { + string pemText = @" + Test that this PEM block is skipped since it is not an understood PEM label. + -----BEGIN SLEEPING----- + zzzz + -----END SLEEPING----- + -----BEGIN PUBLIC KEY----- + c2xlZXA= + -----END PUBLIC KEY-----"; + + static void ImportSubjectPublicKeyInfo(ReadOnlySpan source, out int bytesRead) + { + ReadOnlySpan expected = new byte[] { 0x73, 0x6c, 0x65, 0x65, 0x70 }; + AssertExtensions.SequenceEqual(expected, source); + bytesRead = expected.Length; + } + + using (ImportAsymmetricAlgorithm alg = new ImportAsymmetricAlgorithm()) + { + alg.ImportSubjectPublicKeyInfoImpl = ImportSubjectPublicKeyInfo; + alg.ImportFromPem(pemText); + } + } + + [Fact] + public static void ImportFromPem_AcceptsPkcs8PrivateKey() + { + string pemText = @" + Test that this PEM block is skipped since it is not an understood PEM label. + -----BEGIN SLEEPING----- + zzzz + -----END SLEEPING----- + -----BEGIN PRIVATE KEY----- + c2xlZXA= + -----END PRIVATE KEY-----"; + + static void ImportPkcs8PrivateKey(ReadOnlySpan source, out int bytesRead) + { + ReadOnlySpan expected = new byte[] { 0x73, 0x6c, 0x65, 0x65, 0x70 }; + AssertExtensions.SequenceEqual(expected, source); + bytesRead = expected.Length; + } + + using (ImportAsymmetricAlgorithm alg = new ImportAsymmetricAlgorithm()) + { + alg.ImportPkcs8PrivateKeyImpl = ImportPkcs8PrivateKey; + alg.ImportFromPem(pemText); + } + } + + [Fact] + public static void ImportFromPem_AcceptsEncryptedPkcs8PrivateKey_PasswordBytes() + { + string pemText = @" + Test that this PEM block is skipped since it is not an understood PEM label. + -----BEGIN SLEEPING----- + zzzz + -----END SLEEPING----- + -----BEGIN ENCRYPTED PRIVATE KEY----- + c2xlZXA= + -----END ENCRYPTED PRIVATE KEY-----"; + byte[] pemPassword = new byte[] { 1, 2, 3, 4, 5 }; + + void ImportEncryptedPkcs8PrivateKey( + ReadOnlySpan passwordBytes, + ReadOnlySpan source, + out int bytesRead) + { + ReadOnlySpan expected = new byte[] { 0x73, 0x6c, 0x65, 0x65, 0x70 }; + AssertExtensions.SequenceEqual(expected, source); + AssertExtensions.SequenceEqual(pemPassword, passwordBytes); + bytesRead = expected.Length; + } + + using (ImportAsymmetricAlgorithm alg = new ImportAsymmetricAlgorithm()) + { + alg.ImportEncryptedPkcs8PrivateKeyByteFunc = ImportEncryptedPkcs8PrivateKey; + alg.ImportFromEncryptedPem(pemText, pemPassword); + } + } + + [Fact] + public static void ImportFromPem_AcceptsEncryptedPkcs8PrivateKey_PasswordChars() + { + string pemText = @" + Test that this PEM block is skipped since it is not an understood PEM label. + -----BEGIN SLEEPING----- + zzzz + -----END SLEEPING----- + -----BEGIN ENCRYPTED PRIVATE KEY----- + c2xlZXA= + -----END ENCRYPTED PRIVATE KEY-----"; + string pemPassword = "PLACEHOLDER"; + + void ImportEncryptedPkcs8PrivateKey( + ReadOnlySpan password, + ReadOnlySpan source, + out int bytesRead) + { + ReadOnlySpan expected = new byte[] { 0x73, 0x6c, 0x65, 0x65, 0x70 }; + AssertExtensions.SequenceEqual(expected, source); + AssertExtensions.SequenceEqual(pemPassword, password); + bytesRead = expected.Length; + } + + using (ImportAsymmetricAlgorithm alg = new ImportAsymmetricAlgorithm()) + { + alg.ImportEncryptedPkcs8PrivateKeyCharFunc = ImportEncryptedPkcs8PrivateKey; + alg.ImportFromEncryptedPem(pemText, pemPassword); + } + } + + [Fact] + public static void ImportFromPem_AmbiguousKey() + { + string pemText = @" + -----BEGIN PUBLIC KEY----- + c2xlZXA= + -----END PUBLIC KEY----- + -----BEGIN PUBLIC KEY----- + Y29mZmVl + -----END PUBLIC KEY-----"; + + using (ImportAsymmetricAlgorithm alg = new ImportAsymmetricAlgorithm()) + { + AssertExtensions.Throws("input", () => alg.ImportFromPem(pemText)); + } + } + + [Fact] + public static void ImportFromPem_Encrypted_AmbiguousKey() + { + string pemText = @" + -----BEGIN ENCRYPTED PRIVATE KEY----- + c2xlZXA= + -----END ENCRYPTED PRIVATE KEY----- + -----BEGIN ENCRYPTED PRIVATE KEY----- + Y29mZmVl + -----END ENCRYPTED PRIVATE KEY-----"; + string pemPassword = "PLACEHOLDER"; + + using (ImportAsymmetricAlgorithm alg = new ImportAsymmetricAlgorithm()) + { + AssertExtensions.Throws("input", () => alg.ImportFromEncryptedPem(pemText, pemPassword)); + } + } + + [Fact] + public static void ImportFromPem_NoUnderstoodPemLabel() + { + string pemText = @" + -----BEGIN SLEEPING----- + zzzz + -----END SLEEPING-----"; + + using (ImportAsymmetricAlgorithm alg = new ImportAsymmetricAlgorithm()) + { + AssertExtensions.Throws("input", () => alg.ImportFromPem(pemText)); + } + } + + [Fact] + public static void ImportFromPem_Encrypted_NoUnderstoodPemLabel() + { + string pemText = @" + -----BEGIN SLEEPING----- + zzzz + -----END SLEEPING-----"; + string pemPassword = "PLACEHOLDER"; + + using (ImportAsymmetricAlgorithm alg = new ImportAsymmetricAlgorithm()) + { + AssertExtensions.Throws("input", () => alg.ImportFromEncryptedPem(pemText, pemPassword)); + } + } + + [Fact] + public static void ImportFromPem_EncryptedPemWithoutPassword() + { + string pemText = @" + -----BEGIN ENCRYPTED PRIVATE KEY----- + c2xlZXA= + -----END ENCRYPTED PRIVATE KEY-----"; + + using (ImportAsymmetricAlgorithm alg = new ImportAsymmetricAlgorithm()) + { + AssertExtensions.Throws("input", () => alg.ImportFromPem(pemText)); + } + } + + [Fact] + public static void ImportFromPem_NotEncryptedWithPassword() + { + string pemText = @" + -----BEGIN PRIVATE KEY----- + c2xlZXA= + -----END PRIVATE KEY-----"; + string pemPassword = "PLACEHOLDER"; + + using (ImportAsymmetricAlgorithm alg = new ImportAsymmetricAlgorithm()) + { + AssertExtensions.Throws("input", () => alg.ImportFromEncryptedPem(pemText, pemPassword)); + } + } + + private class ImportAsymmetricAlgorithm : AsymmetricAlgorithm + { + public delegate void ImportSubjectPublicKeyInfoFunc(ReadOnlySpan source, out int bytesRead); + public delegate void ImportPkcs8PrivateKeyFunc(ReadOnlySpan source, out int bytesRead); + public delegate void ImportEncryptedPkcs8PrivateKeyFunc( + ReadOnlySpan password, + ReadOnlySpan source, + out int bytesRead); + + public ImportSubjectPublicKeyInfoFunc ImportSubjectPublicKeyInfoImpl { get; set; } + public ImportPkcs8PrivateKeyFunc ImportPkcs8PrivateKeyImpl { get; set; } + public ImportEncryptedPkcs8PrivateKeyFunc ImportEncryptedPkcs8PrivateKeyByteFunc { get; set; } + public ImportEncryptedPkcs8PrivateKeyFunc ImportEncryptedPkcs8PrivateKeyCharFunc { get; set; } + + public override void ImportSubjectPublicKeyInfo(ReadOnlySpan source, out int bytesRead) => + ImportSubjectPublicKeyInfoImpl(source, out bytesRead); + + public override void ImportPkcs8PrivateKey(ReadOnlySpan source, out int bytesRead) => + ImportPkcs8PrivateKeyImpl(source, out bytesRead); + + public override void ImportEncryptedPkcs8PrivateKey( + ReadOnlySpan passwordBytes, + ReadOnlySpan source, + out int bytesRead) + { + ImportEncryptedPkcs8PrivateKeyByteFunc(passwordBytes, source, out bytesRead); + } + + public override void ImportEncryptedPkcs8PrivateKey( + ReadOnlySpan password, + ReadOnlySpan source, + out int bytesRead) + { + ImportEncryptedPkcs8PrivateKeyCharFunc(password, source, out bytesRead); + } + } + } +} diff --git a/src/libraries/System.Security.Cryptography/tests/System.Security.Cryptography.Tests.csproj b/src/libraries/System.Security.Cryptography/tests/System.Security.Cryptography.Tests.csproj index aa118f022bbf0..fce17560950c6 100644 --- a/src/libraries/System.Security.Cryptography/tests/System.Security.Cryptography.Tests.csproj +++ b/src/libraries/System.Security.Cryptography/tests/System.Security.Cryptography.Tests.csproj @@ -25,6 +25,7 @@ +