Convert [DSA/RSA/Ecc]SecurityTransforms and X509SignatureGenerators to new ASN.1...
authorFilip Navara <filip.navara@gmail.com>
Fri, 7 Sep 2018 17:59:36 +0000 (19:59 +0200)
committerJeremy Barton <jbarton@microsoft.com>
Fri, 7 Sep 2018 17:59:36 +0000 (10:59 -0700)
This changes a lot of types designed for AsnSerializer to use the AsnXml code generator, and moves a number of those types from S.S.C.Algorithms to Common because the SecurityTransforms types are dual-compiled.

The workflow is similar to:

* Change all of the SecurityTransforms types to use the new types added during the key import/export feature.
* Change those types to use AsnXml generated code instead of AsnSerializer
* Move the types to Common source to fix S.S.C.X509Certificates build breaks
* Now that the types are already included in S.S.C.X509Certificates, make X509SignatureGenerator types use them, too.

Commit migrated from https://github.com/dotnet/corefx/commit/a0cfc0492df974ebb2b9293e4d5640e1c1505263

89 files changed:
src/libraries/Common/src/Internal/Cryptography/AsymmetricAlgorithmHelpers.Der.cs
src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.SecKeyRef.Export.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1/AlgorithmIdentifierAsn.manual.cs [moved from src/libraries/Common/src/System/Security/Cryptography/Asn1/AlgorithmIdentifierAsn.cs with 52% similarity]
src/libraries/Common/src/System/Security/Cryptography/Asn1/AlgorithmIdentifierAsn.xml [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/AlgorithmIdentifierAsn.xml.cs [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/AttributeAsn.cs [deleted file]
src/libraries/Common/src/System/Security/Cryptography/Asn1/AttributeAsn.xml [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/AttributeAsn.xml.cs [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/CurveAsn.xml [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/CurveAsn.xml.cs [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/DssParms.xml [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/DssParms.xml.cs [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/ECDomainParameters.xml [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/ECDomainParameters.xml.cs [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/ECPrivateKey.xml [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/ECPrivateKey.xml.cs [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/EncryptedPrivateKeyInfoAsn.cs [deleted file]
src/libraries/Common/src/System/Security/Cryptography/Asn1/EncryptedPrivateKeyInfoAsn.xml [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/EncryptedPrivateKeyInfoAsn.xml.cs [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/FieldID.xml [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/FieldID.xml.cs [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/PBEParameter.cs [deleted file]
src/libraries/Common/src/System/Security/Cryptography/Asn1/PBEParameter.xml [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/PBEParameter.xml.cs [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/PBES2Params.cs [deleted file]
src/libraries/Common/src/System/Security/Cryptography/Asn1/PBES2Params.xml [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/PBES2Params.xml.cs [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2Params.cs [deleted file]
src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2Params.xml [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2Params.xml.cs [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2SaltChoice.cs [deleted file]
src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2SaltChoice.xml [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2SaltChoice.xml.cs [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/PrivateKeyInfoAsn.cs [deleted file]
src/libraries/Common/src/System/Security/Cryptography/Asn1/PrivateKeyInfoAsn.xml [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/PrivateKeyInfoAsn.xml.cs [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/PssParamsAsn.cs [deleted file]
src/libraries/Common/src/System/Security/Cryptography/Asn1/PssParamsAsn.xml [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/PssParamsAsn.xml.cs [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPrivateKeyAsn.xml [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPrivateKeyAsn.xml.cs [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPublicKeyAsn.xml [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPublicKeyAsn.xml.cs [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/SpecifiedECDomain.xml [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/SpecifiedECDomain.xml.cs [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/SubjectPublicKeyInfoAsn.cs [deleted file]
src/libraries/Common/src/System/Security/Cryptography/Asn1/SubjectPublicKeyInfoAsn.xml [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/SubjectPublicKeyInfoAsn.xml.cs [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/DSAKeyFormatHelper.cs [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/DSASecurityTransforms.cs
src/libraries/Common/src/System/Security/Cryptography/ECDiffieHellmanSecurityTransforms.cs
src/libraries/Common/src/System/Security/Cryptography/EccKeyFormatHelper.cs [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/EccSecurityTransforms.cs
src/libraries/Common/src/System/Security/Cryptography/KeyBlobHelpers.cs
src/libraries/Common/src/System/Security/Cryptography/KeyFormatHelper.cs
src/libraries/Common/src/System/Security/Cryptography/PasswordBasedEncryption.cs
src/libraries/Common/src/System/Security/Cryptography/RSAKeyFormatHelper.cs [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/RSASecurityTransforms.cs
src/libraries/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/Helpers.cs
src/libraries/System.Security.Cryptography.Algorithms/src/Resources/Strings.resx
src/libraries/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj
src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Asn1/CurveAsn.cs [deleted file]
src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Asn1/DSSParms.cs [deleted file]
src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Asn1/DsaPrivateKeyAsn.cs [deleted file]
src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Asn1/ECDomainParameters.cs [deleted file]
src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Asn1/ECPrivateKey.cs [deleted file]
src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Asn1/FieldID.cs [deleted file]
src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Asn1/RSAPrivateKeyAsn.cs [deleted file]
src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Asn1/RSAPublicKeyAsn.cs [deleted file]
src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Asn1/SpecifiedECDomain.cs [deleted file]
src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/DSA.cs
src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellman.cs
src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDsa.cs
src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECParameters.cs
src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/RSA.cs
src/libraries/System.Security.Cryptography.Cng/src/Resources/Strings.resx
src/libraries/System.Security.Cryptography.Cng/src/System.Security.Cryptography.Cng.csproj
src/libraries/System.Security.Cryptography.Encoding/tests/Asn1/Serializer/SimpleDeserialize.cs
src/libraries/System.Security.Cryptography.Encoding/tests/System.Security.Cryptography.Encoding.Tests.csproj
src/libraries/System.Security.Cryptography.OpenSsl/src/Resources/Strings.resx
src/libraries/System.Security.Cryptography.OpenSsl/src/System.Security.Cryptography.OpenSsl.csproj
src/libraries/System.Security.Cryptography.Pkcs/src/System.Security.Cryptography.Pkcs.csproj
src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignerInfoTests.netcoreapp.cs
src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.OSX/X509Pal.cs
src/libraries/System.Security.Cryptography.X509Certificates/src/Resources/Strings.resx
src/libraries/System.Security.Cryptography.X509Certificates/src/System.Security.Cryptography.X509Certificates.csproj
src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/ECDsaX509SignatureGenerator.cs
src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/RSAPkcs1X509SignatureGenerator.cs
src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/RSAPssX509SignatureGenerator.cs

index 060f640..69ab098 100644 (file)
@@ -5,7 +5,9 @@
 using System;
 using System.Diagnostics;
 using System.IO;
+using System.Numerics;
 using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
 
 namespace Internal.Cryptography
 {
@@ -26,10 +28,14 @@ namespace Internal.Cryptography
             // Output is the DER encoded value of CONSTRUCTEDSEQUENCE(INTEGER(r), INTEGER(s)). 
             int halfLength = input.Length / 2;
 
-            byte[][] rEncoded = DerEncoder.SegmentedEncodeUnsignedInteger(input.Slice(0, halfLength));
-            byte[][] sEncoded = DerEncoder.SegmentedEncodeUnsignedInteger(input.Slice(halfLength, halfLength));
-
-            return DerEncoder.ConstructSequence(rEncoded, sEncoded);
+            using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER))
+            {
+                writer.PushSequence();
+                writer.WriteKeyParameterInteger(input.Slice(0, halfLength));
+                writer.WriteKeyParameterInteger(input.Slice(halfLength, halfLength));
+                writer.PopSequence();
+                return writer.Encode();
+            }
         }
 
         /// <summary>
@@ -39,22 +45,18 @@ namespace Internal.Cryptography
         {
             int size = BitsToBytes(fieldSizeBits);
 
-            try
-            {
-                DerSequenceReader reader = new DerSequenceReader(input, inputOffset, inputCount);
-                byte[] rDer = reader.ReadIntegerBytes();
-                byte[] sDer = reader.ReadIntegerBytes();
-                byte[] response = new byte[2 * size];
+            AsnReader reader = new AsnReader(input.AsMemory(inputOffset, inputCount), AsnEncodingRules.DER);
+            AsnReader sequenceReader = reader.ReadSequence();
+            reader.ThrowIfNotEmpty();
+            ReadOnlySpan<byte> rDer = sequenceReader.GetIntegerBytes().Span;
+            ReadOnlySpan<byte> sDer = sequenceReader.GetIntegerBytes().Span;
+            sequenceReader.ThrowIfNotEmpty();
 
-                CopySignatureField(rDer, response, 0, size);
-                CopySignatureField(sDer, response, size, size);
+            byte[] response = new byte[2 * size];
+            CopySignatureField(rDer, response.AsSpan(0, size));
+            CopySignatureField(sDer, response.AsSpan(size, size));
 
-                return response;
-            }
-            catch (InvalidOperationException e)
-            {
-                throw new CryptographicException(SR.Arg_CryptographyException, e);
-            }
+            return response;
         }
 
         public static int BitsToBytes(int bitLength)
@@ -63,30 +65,22 @@ namespace Internal.Cryptography
             return byteLength;
         }
 
-        private static void CopySignatureField(byte[] signatureField, byte[] response, int offset, int fieldLength)
+        private static void CopySignatureField(ReadOnlySpan<byte> signatureField, Span<byte> response)
         {
-            if (signatureField.Length > fieldLength)
+            if (signatureField.Length > response.Length)
             {
                 // The only way this should be true is if the value required a zero-byte-pad.
-                Debug.Assert(signatureField.Length == fieldLength + 1, "signatureField.Length == fieldLength + 1");
+                Debug.Assert(signatureField.Length == response.Length + 1, "signatureField.Length == fieldLength + 1");
                 Debug.Assert(signatureField[0] == 0, "signatureField[0] == 0");
                 Debug.Assert(signatureField[1] > 0x7F, "signatureField[1] > 0x7F");
-
-                Buffer.BlockCopy(signatureField, 1, response, offset, fieldLength);
-            }
-            else if (signatureField.Length == fieldLength)
-            {
-                Buffer.BlockCopy(signatureField, 0, response, offset, fieldLength);
+                signatureField = signatureField.Slice(1);
             }
-            else
-            {
-                // If the field is too short then it needs to be prepended
-                // with zeroes in the response.  Since the array was already
-                // zeroed out, just figure out where we need to start copying.
-                int writeOffset = fieldLength - signatureField.Length;
 
-                Buffer.BlockCopy(signatureField, 0, response, offset + writeOffset, signatureField.Length);
-            }
+            // If the field is too short then it needs to be prepended
+            // with zeroes in the response.  Since the array was already
+            // zeroed out, just figure out where we need to start copying.
+            int writeOffset = response.Length - signatureField.Length;
+            signatureField.CopyTo(response.Slice(writeOffset));
         }
     }
 }
index 91e6d7f..374ca9c 100644 (file)
@@ -31,16 +31,13 @@ internal static partial class Interop
             out SafeCFDataHandle cfDataOut,
             out int pOSStatus);
 
-        internal static DerSequenceReader SecKeyExport(
+        internal static byte[] SecKeyExport(
             SafeSecKeyRefHandle key,
-            bool exportPrivate)
+            bool exportPrivate,
+            string password)
         {
-            // Apple requires all private keys to be exported encrypted, but since we're trying to export
-            // as parsed structures we will need to decrypt it for the user.
-            const string ExportPassword = "DotnetExportPassphrase";
-
             SafeCreateHandle exportPassword = exportPrivate
-                ? CoreFoundation.CFStringCreateWithCString(ExportPassword)
+                ? CoreFoundation.CFStringCreateWithCString(password)
                 : s_nullExportString;
 
             int ret;
@@ -82,137 +79,7 @@ internal static partial class Interop
                 exportedData = CoreFoundation.CFGetData(cfData);
             }
 
-            DerSequenceReader reader = new DerSequenceReader(exportedData);
-
-            if (!exportPrivate)
-            {
-                return reader;
-            }
-
-            byte tag = reader.PeekTag();
-
-            // PKCS#8 defines two structures, PrivateKeyInfo, which starts with an integer,
-            // and EncryptedPrivateKey, which starts with an encryption algorithm (DER sequence).
-            if (tag == (byte)DerSequenceReader.DerTag.Integer)
-            {
-                return reader;
-            }
-
-            const byte ConstructedSequence =
-                DerSequenceReader.ConstructedFlag | (byte)DerSequenceReader.DerTag.Sequence;
-
-            if (tag == ConstructedSequence)
-            {
-                return ReadEncryptedPkcs8Blob(ExportPassword, reader);
-            }
-
-            Debug.Fail($"Data was neither PrivateKey or EncryptedPrivateKey: {tag:X2}");
-            throw new CryptographicException();
-        }
-
-        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA5350", Justification = "3DES identified from payload by OID")]
-        private static DerSequenceReader ReadEncryptedPkcs8Blob(string passphrase, DerSequenceReader reader)
-        {
-            // EncryptedPrivateKeyInfo::= SEQUENCE {
-            //    encryptionAlgorithm EncryptionAlgorithmIdentifier,
-            //    encryptedData        EncryptedData }
-            //
-            // EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
-            //
-            // EncryptedData ::= OCTET STRING
-            DerSequenceReader algorithmIdentifier = reader.ReadSequence();
-            string algorithmOid = algorithmIdentifier.ReadOidAsString();
-
-            // PBES2 (Password-Based Encryption Scheme 2)
-            if (algorithmOid != OidPbes2)
-            {
-                Debug.Fail($"Expected PBES2 ({OidPbes2}), got {algorithmOid}");
-                throw new CryptographicException();
-            }
-
-            // PBES2-params ::= SEQUENCE {
-            //    keyDerivationFunc AlgorithmIdentifier { { PBES2 - KDFs} },
-            //    encryptionScheme AlgorithmIdentifier { { PBES2 - Encs} }
-            // }
-
-            DerSequenceReader pbes2Params = algorithmIdentifier.ReadSequence();
-            algorithmIdentifier = pbes2Params.ReadSequence();
-
-            string kdfOid = algorithmIdentifier.ReadOidAsString();
-
-            // PBKDF2 (Password-Based Key Derivation Function 2)
-            if (kdfOid != OidPbkdf2)
-            {
-                Debug.Fail($"Expected PBKDF2 ({OidPbkdf2}), got {kdfOid}");
-                throw new CryptographicException();
-            }
-
-            // PBKDF2-params ::= SEQUENCE {
-            //   salt CHOICE {
-            //     specified OCTET STRING,
-            //     otherSource AlgorithmIdentifier { { PBKDF2 - SaltSources} }
-            //   },
-            //   iterationCount INTEGER (1..MAX),
-            //   keyLength INTEGER(1..MAX) OPTIONAL,
-            //   prf AlgorithmIdentifier { { PBKDF2 - PRFs} }  DEFAULT algid - hmacWithSHA1
-            // }
-            DerSequenceReader pbkdf2Params = algorithmIdentifier.ReadSequence();
-
-            byte[] salt = pbkdf2Params.ReadOctetString();
-            int iterCount = pbkdf2Params.ReadInteger();
-            int keySize = -1;
-
-            if (pbkdf2Params.HasData && pbkdf2Params.PeekTag() == (byte)DerSequenceReader.DerTag.Integer)
-            {
-                keySize = pbkdf2Params.ReadInteger();
-            }
-
-            if (pbkdf2Params.HasData)
-            {
-                string prfOid = pbkdf2Params.ReadOidAsString();
-
-                // SHA-1 is the only hash algorithm our PBKDF2 supports.
-                if (prfOid != OidSha1)
-                {
-                    Debug.Fail($"Expected SHA1 ({OidSha1}), got {prfOid}");
-                    throw new CryptographicException();
-                }
-            }
-
-            DerSequenceReader encryptionScheme = pbes2Params.ReadSequence();
-            string cipherOid = encryptionScheme.ReadOidAsString();
-
-            // DES-EDE3-CBC (TripleDES in CBC mode)
-            if (cipherOid != OidTripleDesCbc)
-            {
-                Debug.Fail($"Expected DES-EDE3-CBC ({OidTripleDesCbc}), got {cipherOid}");
-                throw new CryptographicException();
-            }
-
-            byte[] decrypted;
-
-            using (TripleDES des3 = TripleDES.Create())
-            {
-                if (keySize == -1)
-                {
-                    foreach (KeySizes keySizes in des3.LegalKeySizes)
-                    {
-                        keySize = Math.Max(keySize, keySizes.MaxSize);
-                    }
-                }
-
-                byte[] iv = encryptionScheme.ReadOctetString();
-
-                using (Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(passphrase, salt, iterCount))
-                using (ICryptoTransform decryptor = des3.CreateDecryptor(pbkdf2.GetBytes(keySize / 8), iv))
-                {
-                    byte[] encrypted = reader.ReadOctetString();
-                    decrypted = decryptor.TransformFinalBlock(encrypted, 0, encrypted.Length);
-                }
-            }
-
-            DerSequenceReader pkcs8Reader = new DerSequenceReader(decrypted);
-            return pkcs8Reader;
+            return exportedData;
         }
     }
 }
@@ -6,25 +6,13 @@ using System.Runtime.InteropServices;
 
 namespace System.Security.Cryptography.Asn1
 {
-    [StructLayout(LayoutKind.Sequential)]
-    // https://tools.ietf.org/html/rfc3280#section-4.1.1.2
-    //
-    // AlgorithmIdentifier  ::=  SEQUENCE  {
-    //   algorithm OBJECT IDENTIFIER,
-    //   parameters ANY DEFINED BY algorithm OPTIONAL  }
-    internal partial struct AlgorithmIdentifierAsn
-    {
+       internal partial struct AlgorithmIdentifierAsn
+       {
         internal static readonly ReadOnlyMemory<byte> ExplicitDerNull = new byte[] { 0x05, 0x00 };
 
-        [ObjectIdentifier(PopulateFriendlyName = true)]
-        public Oid Algorithm;
-
-        [AnyValue, OptionalValue]
-        public ReadOnlyMemory<byte>? Parameters;
-
         internal bool Equals(ref AlgorithmIdentifierAsn other)
         {
-            if (Algorithm.Value != other.Algorithm.Value)
+            if (Algorithm != other.Algorithm)
             {
                 return false;
             }
@@ -71,28 +59,5 @@ namespace System.Security.Cryptography.Asn1
 
             return span[1] == 0;
         }
-
-        internal void Encode(AsnWriter writer)
-        {
-            AsnSerializer.Serialize(this, writer);
-        }
-
-        internal static void Decode(AsnReader reader, out AlgorithmIdentifierAsn decoded)
-        {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            ReadOnlyMemory<byte> value = reader.GetEncodedValue();
-            decoded = AsnSerializer.Deserialize<AlgorithmIdentifierAsn>(value, reader.RuleSet);
-        }
-
-        internal static AlgorithmIdentifierAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
-        {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-
-            Decode(reader, out AlgorithmIdentifierAsn decoded);
-            reader.ThrowIfNotEmpty();
-            return decoded;
-        }
     }
 }
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/AlgorithmIdentifierAsn.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/AlgorithmIdentifierAsn.xml
new file mode 100644 (file)
index 0000000..980d0f2
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+  xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+  name="AlgorithmIdentifierAsn"
+  namespace="System.Security.Cryptography.Asn1">
+    
+  <!--
+    https://tools.ietf.org/html/rfc3280#section-4.1.1.2
+
+    AlgorithmIdentifier ::= SEQUENCE {
+        algorithm OBJECT IDENTIFIER,
+        parameters ANY DEFINED BY algorithm OPTIONAL
+    }
+  -->
+  <asn:ObjectIdentifier name="Algorithm" />
+  <asn:AnyValue name="Parameters" optional="true" />
+</asn:Sequence>
\ No newline at end of file
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/AlgorithmIdentifierAsn.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/AlgorithmIdentifierAsn.xml.cs
new file mode 100644 (file)
index 0000000..aa027e4
--- /dev/null
@@ -0,0 +1,74 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+    [StructLayout(LayoutKind.Sequential)]
+    internal partial struct AlgorithmIdentifierAsn
+    {
+        internal Oid Algorithm;
+        internal ReadOnlyMemory<byte>? Parameters;
+      
+        internal void Encode(AsnWriter writer)
+        {
+            Encode(writer, Asn1Tag.Sequence);
+        }
+    
+        internal void Encode(AsnWriter writer, Asn1Tag tag)
+        {
+            writer.PushSequence(tag);
+            
+            writer.WriteObjectIdentifier(Algorithm);
+
+            if (Parameters.HasValue)
+            {
+                writer.WriteEncodedValue(Parameters.Value);
+            }
+
+            writer.PopSequence(tag);
+        }
+
+        internal static AlgorithmIdentifierAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+        }
+        
+        internal static AlgorithmIdentifierAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            AsnReader reader = new AsnReader(encoded, ruleSet);
+            
+            Decode(reader, expectedTag, out AlgorithmIdentifierAsn decoded);
+            reader.ThrowIfNotEmpty();
+            return decoded;
+        }
+
+        internal static void Decode(AsnReader reader, out AlgorithmIdentifierAsn decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            Decode(reader, Asn1Tag.Sequence, out decoded);
+        }
+
+        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out AlgorithmIdentifierAsn decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            decoded = default;
+            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+            
+            decoded.Algorithm = sequenceReader.ReadObjectIdentifier();
+
+            if (sequenceReader.HasData)
+            {
+                decoded.Parameters = sequenceReader.GetEncodedValue();
+            }
+
+
+            sequenceReader.ThrowIfNotEmpty();
+        }
+    }
+}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/AttributeAsn.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/AttributeAsn.cs
deleted file mode 100644 (file)
index 2a4cb34..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-// 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.Runtime.InteropServices;
-
-namespace System.Security.Cryptography.Asn1
-{
-    // https://tools.ietf.org/html/rfc5652#section-5.3
-    //
-    // Attribute ::= SEQUENCE {
-    //   attrType OBJECT IDENTIFIER,
-    //   attrValues SET OF AttributeValue }
-    //
-    // AttributeValue ::= ANY
-    [StructLayout(LayoutKind.Sequential)]
-    internal struct AttributeAsn
-    {
-        public Oid AttrType;
-
-        [AnyValue]
-        public ReadOnlyMemory<byte> AttrValues;
-
-        internal void Encode(AsnWriter writer)
-        {
-            AsnSerializer.Serialize(this, writer);
-        }
-
-        internal static void Decode(AsnReader reader, out AttributeAsn decoded)
-        {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            ReadOnlyMemory<byte> value = reader.GetEncodedValue();
-            decoded = AsnSerializer.Deserialize<AttributeAsn>(value, reader.RuleSet);
-        }
-    }
-}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/AttributeAsn.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/AttributeAsn.xml
new file mode 100644 (file)
index 0000000..62204d1
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+  xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+  name="AttributeAsn"
+  namespace="System.Security.Cryptography.Asn1">
+
+  <!--
+    https://tools.ietf.org/html/rfc5652#section-5.3
+
+    Attribute ::= SEQUENCE {
+        attrType OBJECT IDENTIFIER,
+        attrValues SET OF AttributeValue
+    }
+
+    AttributeValue ::= ANY
+  -->
+  <asn:ObjectIdentifier name="AttrType" />
+  <asn:AnyValue name="AttrValues" />
+</asn:Sequence>
\ No newline at end of file
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/AttributeAsn.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/AttributeAsn.xml.cs
new file mode 100644 (file)
index 0000000..5a27a82
--- /dev/null
@@ -0,0 +1,64 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+    [StructLayout(LayoutKind.Sequential)]
+    internal partial struct AttributeAsn
+    {
+        internal Oid AttrType;
+        internal ReadOnlyMemory<byte> AttrValues;
+      
+        internal void Encode(AsnWriter writer)
+        {
+            Encode(writer, Asn1Tag.Sequence);
+        }
+    
+        internal void Encode(AsnWriter writer, Asn1Tag tag)
+        {
+            writer.PushSequence(tag);
+            
+            writer.WriteObjectIdentifier(AttrType);
+            writer.WriteEncodedValue(AttrValues);
+            writer.PopSequence(tag);
+        }
+
+        internal static AttributeAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+        }
+        
+        internal static AttributeAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            AsnReader reader = new AsnReader(encoded, ruleSet);
+            
+            Decode(reader, expectedTag, out AttributeAsn decoded);
+            reader.ThrowIfNotEmpty();
+            return decoded;
+        }
+
+        internal static void Decode(AsnReader reader, out AttributeAsn decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            Decode(reader, Asn1Tag.Sequence, out decoded);
+        }
+
+        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out AttributeAsn decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            decoded = default;
+            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+            
+            decoded.AttrType = sequenceReader.ReadObjectIdentifier();
+            decoded.AttrValues = sequenceReader.GetEncodedValue();
+
+            sequenceReader.ThrowIfNotEmpty();
+        }
+    }
+}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/CurveAsn.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/CurveAsn.xml
new file mode 100644 (file)
index 0000000..9c02e27
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+  xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+  name="CurveAsn"
+  namespace="System.Security.Cryptography.Asn1">
+
+  <!--
+    https://www.secg.org/sec1-v2.pdf, C.2
+
+    Curve ::= SEQUENCE {
+        a FieldElement,
+        b FieldElement,
+        seed BIT STRING OPTIONAL
+        - Shall be present if used in SpecifiedECDomain
+        - with version equal to ecdpVer2 or ecdpVer3
+    }
+
+    FieldElement ::= OCTET STRING
+  -->
+  <asn:OctetString name="A" />
+  <asn:OctetString name="B" />
+  <asn:BitString name="Seed" optional="true" />
+</asn:Sequence>
\ No newline at end of file
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/CurveAsn.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/CurveAsn.xml.cs
new file mode 100644 (file)
index 0000000..a667fa6
--- /dev/null
@@ -0,0 +1,104 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+    [StructLayout(LayoutKind.Sequential)]
+    internal partial struct CurveAsn
+    {
+        internal ReadOnlyMemory<byte> A;
+        internal ReadOnlyMemory<byte> B;
+        internal ReadOnlyMemory<byte>? Seed;
+      
+        internal void Encode(AsnWriter writer)
+        {
+            Encode(writer, Asn1Tag.Sequence);
+        }
+    
+        internal void Encode(AsnWriter writer, Asn1Tag tag)
+        {
+            writer.PushSequence(tag);
+            
+            writer.WriteOctetString(A.Span);
+            writer.WriteOctetString(B.Span);
+
+            if (Seed.HasValue)
+            {
+                writer.WriteBitString(Seed.Value.Span);
+            }
+
+            writer.PopSequence(tag);
+        }
+
+        internal static CurveAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+        }
+        
+        internal static CurveAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            AsnReader reader = new AsnReader(encoded, ruleSet);
+            
+            Decode(reader, expectedTag, out CurveAsn decoded);
+            reader.ThrowIfNotEmpty();
+            return decoded;
+        }
+
+        internal static void Decode(AsnReader reader, out CurveAsn decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            Decode(reader, Asn1Tag.Sequence, out decoded);
+        }
+
+        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out CurveAsn decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            decoded = default;
+            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+            
+
+            if (sequenceReader.TryGetPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpA))
+            {
+                decoded.A = tmpA;
+            }
+            else
+            {
+                decoded.A = sequenceReader.ReadOctetString();
+            }
+
+
+            if (sequenceReader.TryGetPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpB))
+            {
+                decoded.B = tmpB;
+            }
+            else
+            {
+                decoded.B = sequenceReader.ReadOctetString();
+            }
+
+
+            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.PrimitiveBitString))
+            {
+
+                if (sequenceReader.TryGetPrimitiveBitStringValue(out _, out ReadOnlyMemory<byte> tmpSeed))
+                {
+                    decoded.Seed = tmpSeed;
+                }
+                else
+                {
+                    decoded.Seed = sequenceReader.ReadBitString(out _);
+                }
+
+            }
+
+
+            sequenceReader.ThrowIfNotEmpty();
+        }
+    }
+}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/DssParms.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/DssParms.xml
new file mode 100644 (file)
index 0000000..687bf3d
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+  xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+  name="DssParms"
+  namespace="System.Security.Cryptography.Asn1">
+
+  <!--
+    https://tools.ietf.org/html/rfc3279#section-2.3.2
+
+    Dss-Parms ::= SEQUENCE {
+        p             INTEGER,
+        q             INTEGER,
+        g             INTEGER
+    }
+  -->
+  <asn:Integer name="P" />
+  <asn:Integer name="Q" />
+  <asn:Integer name="G" />
+</asn:Sequence>
\ No newline at end of file
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/DssParms.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/DssParms.xml.cs
new file mode 100644 (file)
index 0000000..dae965e
--- /dev/null
@@ -0,0 +1,67 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+    [StructLayout(LayoutKind.Sequential)]
+    internal partial struct DssParms
+    {
+        internal System.Numerics.BigInteger P;
+        internal System.Numerics.BigInteger Q;
+        internal System.Numerics.BigInteger G;
+      
+        internal void Encode(AsnWriter writer)
+        {
+            Encode(writer, Asn1Tag.Sequence);
+        }
+    
+        internal void Encode(AsnWriter writer, Asn1Tag tag)
+        {
+            writer.PushSequence(tag);
+            
+            writer.WriteInteger(P);
+            writer.WriteInteger(Q);
+            writer.WriteInteger(G);
+            writer.PopSequence(tag);
+        }
+
+        internal static DssParms Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+        }
+        
+        internal static DssParms Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            AsnReader reader = new AsnReader(encoded, ruleSet);
+            
+            Decode(reader, expectedTag, out DssParms decoded);
+            reader.ThrowIfNotEmpty();
+            return decoded;
+        }
+
+        internal static void Decode(AsnReader reader, out DssParms decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            Decode(reader, Asn1Tag.Sequence, out decoded);
+        }
+
+        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out DssParms decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            decoded = default;
+            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+            
+            decoded.P = sequenceReader.GetInteger();
+            decoded.Q = sequenceReader.GetInteger();
+            decoded.G = sequenceReader.GetInteger();
+
+            sequenceReader.ThrowIfNotEmpty();
+        }
+    }
+}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/ECDomainParameters.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/ECDomainParameters.xml
new file mode 100644 (file)
index 0000000..2ca6f12
--- /dev/null
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Choice
+  xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+  name="ECDomainParameters"
+  namespace="System.Security.Cryptography.Asn1">
+
+  <!--
+    https://www.secg.org/sec1-v2.pdf, C.2
+
+    ECDomainParameters{ECDOMAIN:IOSet} ::= CHOICE {
+        specified SpecifiedECDomain,
+        named ECDOMAIN.&id({IOSet}),
+        implicitCA NULL
+    }
+  -->
+  <asn:AsnType name="Specified" typeName="System.Security.Cryptography.Asn1.SpecifiedECDomain" />
+  <asn:ObjectIdentifier name="Named" />
+</asn:Choice>
\ No newline at end of file
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/ECDomainParameters.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/ECDomainParameters.xml.cs
new file mode 100644 (file)
index 0000000..b832003
--- /dev/null
@@ -0,0 +1,95 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+    [StructLayout(LayoutKind.Sequential)]
+    internal partial struct ECDomainParameters
+    {
+        internal System.Security.Cryptography.Asn1.SpecifiedECDomain? Specified;
+        internal Oid Named;
+
+#if DEBUG
+        static ECDomainParameters()
+        {
+            var usedTags = new System.Collections.Generic.Dictionary<Asn1Tag, string>();
+            Action<Asn1Tag, string> ensureUniqueTag = (tag, fieldName) =>
+            {
+                if (usedTags.TryGetValue(tag, out string existing))
+                {
+                    throw new InvalidOperationException($"Tag '{tag}' is in use by both '{existing}' and '{fieldName}'");
+                }
+
+                usedTags.Add(tag, fieldName);
+            };
+            
+            ensureUniqueTag(Asn1Tag.Sequence, "Specified");
+            ensureUniqueTag(Asn1Tag.ObjectIdentifier, "Named");
+        }
+#endif
+
+        internal void Encode(AsnWriter writer)
+        {
+            bool wroteValue = false; 
+            
+            if (Specified.HasValue)
+            {
+                if (wroteValue)
+                    throw new CryptographicException();
+                
+                Specified.Value.Encode(writer);
+                wroteValue = true;
+            }
+
+            if (Named != null)
+            {
+                if (wroteValue)
+                    throw new CryptographicException();
+                
+                writer.WriteObjectIdentifier(Named);
+                wroteValue = true;
+            }
+
+            if (!wroteValue)
+            {
+                throw new CryptographicException();
+            }
+        }
+
+        internal static ECDomainParameters Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            AsnReader reader = new AsnReader(encoded, ruleSet);
+            
+            Decode(reader, out ECDomainParameters decoded);
+            reader.ThrowIfNotEmpty();
+            return decoded;
+        }
+
+        internal static void Decode(AsnReader reader, out ECDomainParameters decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            decoded = default;
+            Asn1Tag tag = reader.PeekTag();
+            
+            if (tag.HasSameClassAndValue(Asn1Tag.Sequence))
+            {
+                System.Security.Cryptography.Asn1.SpecifiedECDomain tmpSpecified;
+                System.Security.Cryptography.Asn1.SpecifiedECDomain.Decode(reader, out tmpSpecified);
+                decoded.Specified = tmpSpecified;
+
+            }
+            else if (tag.HasSameClassAndValue(Asn1Tag.ObjectIdentifier))
+            {
+                decoded.Named = reader.ReadObjectIdentifier();
+            }
+            else
+            {
+                throw new CryptographicException();
+            }
+        }
+    }
+}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/ECPrivateKey.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/ECPrivateKey.xml
new file mode 100644 (file)
index 0000000..c881bb0
--- /dev/null
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+  xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+  name="ECPrivateKey"
+  namespace="System.Security.Cryptography.Asn1">
+
+  <!--
+    https://www.secg.org/sec1-v2.pdf, C.4
+
+    ECPrivateKey ::= SEQUENCE {
+        version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
+        privateKey OCTET STRING,
+        parameters [0] ECDomainParameters {{ SECGCurveNames }} OPTIONAL,
+        publicKey [1] BIT STRING OPTIONAL
+    }
+  -->
+  <asn:Integer name="Version" backingType="byte" />
+  <asn:OctetString name="PrivateKey" />
+  <asn:AsnType name="Parameters" typeName="System.Security.Cryptography.Asn1.ECDomainParameters" explicitTag="0" optional="true" />
+  <asn:BitString name="PublicKey" explicitTag="1" optional="true" />
+</asn:Sequence>
\ No newline at end of file
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/ECPrivateKey.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/ECPrivateKey.xml.cs
new file mode 100644 (file)
index 0000000..963fcdd
--- /dev/null
@@ -0,0 +1,125 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+    [StructLayout(LayoutKind.Sequential)]
+    internal partial struct ECPrivateKey
+    {
+        internal byte Version;
+        internal ReadOnlyMemory<byte> PrivateKey;
+        internal System.Security.Cryptography.Asn1.ECDomainParameters? Parameters;
+        internal ReadOnlyMemory<byte>? PublicKey;
+      
+        internal void Encode(AsnWriter writer)
+        {
+            Encode(writer, Asn1Tag.Sequence);
+        }
+    
+        internal void Encode(AsnWriter writer, Asn1Tag tag)
+        {
+            writer.PushSequence(tag);
+            
+            writer.WriteInteger(Version);
+            writer.WriteOctetString(PrivateKey.Span);
+
+            if (Parameters.HasValue)
+            {
+                writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
+                Parameters.Value.Encode(writer);
+                writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
+            }
+
+
+            if (PublicKey.HasValue)
+            {
+                writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 1));
+                writer.WriteBitString(PublicKey.Value.Span);
+                writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 1));
+            }
+
+            writer.PopSequence(tag);
+        }
+
+        internal static ECPrivateKey Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+        }
+        
+        internal static ECPrivateKey Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            AsnReader reader = new AsnReader(encoded, ruleSet);
+            
+            Decode(reader, expectedTag, out ECPrivateKey decoded);
+            reader.ThrowIfNotEmpty();
+            return decoded;
+        }
+
+        internal static void Decode(AsnReader reader, out ECPrivateKey decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            Decode(reader, Asn1Tag.Sequence, out decoded);
+        }
+
+        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out ECPrivateKey decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            decoded = default;
+            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnReader explicitReader;
+            
+
+            if (!sequenceReader.TryReadUInt8(out decoded.Version))
+            {
+                sequenceReader.ThrowIfNotEmpty();
+            }
+
+
+            if (sequenceReader.TryGetPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpPrivateKey))
+            {
+                decoded.PrivateKey = tmpPrivateKey;
+            }
+            else
+            {
+                decoded.PrivateKey = sequenceReader.ReadOctetString();
+            }
+
+
+            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
+            {
+                explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
+                System.Security.Cryptography.Asn1.ECDomainParameters tmpParameters;
+                System.Security.Cryptography.Asn1.ECDomainParameters.Decode(explicitReader, out tmpParameters);
+                decoded.Parameters = tmpParameters;
+
+                explicitReader.ThrowIfNotEmpty();
+            }
+
+
+            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 1)))
+            {
+                explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 1));
+
+                if (explicitReader.TryGetPrimitiveBitStringValue(out _, out ReadOnlyMemory<byte> tmpPublicKey))
+                {
+                    decoded.PublicKey = tmpPublicKey;
+                }
+                else
+                {
+                    decoded.PublicKey = explicitReader.ReadBitString(out _);
+                }
+
+                explicitReader.ThrowIfNotEmpty();
+            }
+
+
+            sequenceReader.ThrowIfNotEmpty();
+        }
+    }
+}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/EncryptedPrivateKeyInfoAsn.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/EncryptedPrivateKeyInfoAsn.cs
deleted file mode 100644 (file)
index 65b75a0..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-// 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.Runtime.InteropServices;
-
-namespace System.Security.Cryptography.Asn1
-{
-    // https://tools.ietf.org/html/rfc5208#section-6
-    //
-    // EncryptedPrivateKeyInfo ::= SEQUENCE {
-    //  encryptionAlgorithm  EncryptionAlgorithmIdentifier,
-    //  encryptedData        EncryptedData }
-    //
-    // EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
-    // EncryptedData ::= OCTET STRING
-    [StructLayout(LayoutKind.Sequential)]
-    internal struct EncryptedPrivateKeyInfoAsn
-    {
-        public AlgorithmIdentifierAsn EncryptionAlgorithm;
-
-        [OctetString]
-        public ReadOnlyMemory<byte> EncryptedData;
-    }
-}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/EncryptedPrivateKeyInfoAsn.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/EncryptedPrivateKeyInfoAsn.xml
new file mode 100644 (file)
index 0000000..e15636e
--- /dev/null
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+  xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+  name="EncryptedPrivateKeyInfoAsn"
+  namespace="System.Security.Cryptography.Asn1">
+
+  <!--
+    https://tools.ietf.org/html/rfc5208#section-6
+
+    EncryptedPrivateKeyInfo ::= SEQUENCE {
+        encryptionAlgorithm  EncryptionAlgorithmIdentifier,
+        encryptedData        EncryptedData
+    }
+
+    EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
+    EncryptedData ::= OCTET STRING
+  -->
+  <asn:AsnType name="EncryptionAlgorithm" typeName="System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn" />
+  <asn:OctetString name="EncryptedData" />
+</asn:Sequence>
\ No newline at end of file
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/EncryptedPrivateKeyInfoAsn.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/EncryptedPrivateKeyInfoAsn.xml.cs
new file mode 100644 (file)
index 0000000..451a7a6
--- /dev/null
@@ -0,0 +1,73 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+    [StructLayout(LayoutKind.Sequential)]
+    internal partial struct EncryptedPrivateKeyInfoAsn
+    {
+        internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn EncryptionAlgorithm;
+        internal ReadOnlyMemory<byte> EncryptedData;
+      
+        internal void Encode(AsnWriter writer)
+        {
+            Encode(writer, Asn1Tag.Sequence);
+        }
+    
+        internal void Encode(AsnWriter writer, Asn1Tag tag)
+        {
+            writer.PushSequence(tag);
+            
+            EncryptionAlgorithm.Encode(writer);
+            writer.WriteOctetString(EncryptedData.Span);
+            writer.PopSequence(tag);
+        }
+
+        internal static EncryptedPrivateKeyInfoAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+        }
+        
+        internal static EncryptedPrivateKeyInfoAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            AsnReader reader = new AsnReader(encoded, ruleSet);
+            
+            Decode(reader, expectedTag, out EncryptedPrivateKeyInfoAsn decoded);
+            reader.ThrowIfNotEmpty();
+            return decoded;
+        }
+
+        internal static void Decode(AsnReader reader, out EncryptedPrivateKeyInfoAsn decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            Decode(reader, Asn1Tag.Sequence, out decoded);
+        }
+
+        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out EncryptedPrivateKeyInfoAsn decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            decoded = default;
+            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+            
+            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(sequenceReader, out decoded.EncryptionAlgorithm);
+
+            if (sequenceReader.TryGetPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpEncryptedData))
+            {
+                decoded.EncryptedData = tmpEncryptedData;
+            }
+            else
+            {
+                decoded.EncryptedData = sequenceReader.ReadOctetString();
+            }
+
+
+            sequenceReader.ThrowIfNotEmpty();
+        }
+    }
+}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/FieldID.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/FieldID.xml
new file mode 100644 (file)
index 0000000..f57c184
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+  xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+  name="FieldID"
+  namespace="System.Security.Cryptography.Asn1">
+
+  <!--
+    https://www.secg.org/sec1-v2.pdf, C.1
+
+    FieldID { FIELD-ID:IOSet } ::= SEQUENCE { - Finite field
+        fieldType FIELD-ID.&id({IOSet}),
+        parameters FIELD-ID.&Type({IOSet}{@fieldType})
+    }
+  -->
+  <asn:ObjectIdentifier name="FieldType" backingType="string" />
+  <asn:AnyValue name="Parameters" />
+</asn:Sequence>
\ No newline at end of file
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/FieldID.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/FieldID.xml.cs
new file mode 100644 (file)
index 0000000..5e1ac8f
--- /dev/null
@@ -0,0 +1,64 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+    [StructLayout(LayoutKind.Sequential)]
+    internal partial struct FieldID
+    {
+        internal string FieldType;
+        internal ReadOnlyMemory<byte> Parameters;
+      
+        internal void Encode(AsnWriter writer)
+        {
+            Encode(writer, Asn1Tag.Sequence);
+        }
+    
+        internal void Encode(AsnWriter writer, Asn1Tag tag)
+        {
+            writer.PushSequence(tag);
+            
+            writer.WriteObjectIdentifier(FieldType);
+            writer.WriteEncodedValue(Parameters);
+            writer.PopSequence(tag);
+        }
+
+        internal static FieldID Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+        }
+        
+        internal static FieldID Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            AsnReader reader = new AsnReader(encoded, ruleSet);
+            
+            Decode(reader, expectedTag, out FieldID decoded);
+            reader.ThrowIfNotEmpty();
+            return decoded;
+        }
+
+        internal static void Decode(AsnReader reader, out FieldID decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            Decode(reader, Asn1Tag.Sequence, out decoded);
+        }
+
+        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out FieldID decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            decoded = default;
+            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+            
+            decoded.FieldType = sequenceReader.ReadObjectIdentifierAsString();
+            decoded.Parameters = sequenceReader.GetEncodedValue();
+
+            sequenceReader.ThrowIfNotEmpty();
+        }
+    }
+}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/PBEParameter.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/PBEParameter.cs
deleted file mode 100644 (file)
index f032b22..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-// 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.Runtime.InteropServices;
-
-namespace System.Security.Cryptography.Asn1
-{
-    // https://tools.ietf.org/html/rfc2898#appendix-A.3
-    //
-    // PBEParameter ::= SEQUENCE {
-    //   salt OCTET STRING (SIZE(8)),
-    //   iterationCount INTEGER }
-    //
-    // The version from PKCS#12 (pkcs-12PbeParams, https://tools.ietf.org/html/rfc7292#appendix-C)
-    // is the same, without limiting the size of the salt value.
-    [StructLayout(LayoutKind.Sequential)]
-    internal struct PBEParameter
-    {
-        [OctetString]
-        public ReadOnlyMemory<byte> Salt;
-
-        // The spec calls out that while there's technically no limit to IterationCount,
-        // that specific platforms may have their own limits.
-        //
-        // This defines ours to uint.MaxValue (and, conveniently, not a negative number)
-        public uint IterationCount;
-    }
-}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/PBEParameter.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/PBEParameter.xml
new file mode 100644 (file)
index 0000000..9062139
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+  xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+  name="PBEParameter"
+  namespace="System.Security.Cryptography.Asn1">
+
+  <!--
+    https://tools.ietf.org/html/rfc2898#appendix-A.3
+
+    PBEParameter ::= SEQUENCE {
+        salt OCTET STRING (SIZE(8)),
+        iterationCount INTEGER
+    }
+    
+    The version from PKCS#12 (pkcs-12PbeParams, https://tools.ietf.org/html/rfc7292#appendix-C)
+    is the same, without limiting the size of the salt value.
+  -->
+  <asn:OctetString name="Salt" />
+  <!--
+    The spec calls out that while there's technically no limit to IterationCount,
+    that specific platforms may have their own limits. This defines ours to int.MaxValue.
+  -->
+  <asn:Integer name="IterationCount" backingType="int" />
+</asn:Sequence>
\ No newline at end of file
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/PBEParameter.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/PBEParameter.xml.cs
new file mode 100644 (file)
index 0000000..75e0ffb
--- /dev/null
@@ -0,0 +1,78 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+    [StructLayout(LayoutKind.Sequential)]
+    internal partial struct PBEParameter
+    {
+        internal ReadOnlyMemory<byte> Salt;
+        internal int IterationCount;
+      
+        internal void Encode(AsnWriter writer)
+        {
+            Encode(writer, Asn1Tag.Sequence);
+        }
+    
+        internal void Encode(AsnWriter writer, Asn1Tag tag)
+        {
+            writer.PushSequence(tag);
+            
+            writer.WriteOctetString(Salt.Span);
+            writer.WriteInteger(IterationCount);
+            writer.PopSequence(tag);
+        }
+
+        internal static PBEParameter Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+        }
+        
+        internal static PBEParameter Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            AsnReader reader = new AsnReader(encoded, ruleSet);
+            
+            Decode(reader, expectedTag, out PBEParameter decoded);
+            reader.ThrowIfNotEmpty();
+            return decoded;
+        }
+
+        internal static void Decode(AsnReader reader, out PBEParameter decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            Decode(reader, Asn1Tag.Sequence, out decoded);
+        }
+
+        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out PBEParameter decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            decoded = default;
+            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+            
+
+            if (sequenceReader.TryGetPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpSalt))
+            {
+                decoded.Salt = tmpSalt;
+            }
+            else
+            {
+                decoded.Salt = sequenceReader.ReadOctetString();
+            }
+
+
+            if (!sequenceReader.TryReadInt32(out decoded.IterationCount))
+            {
+                sequenceReader.ThrowIfNotEmpty();
+            }
+
+
+            sequenceReader.ThrowIfNotEmpty();
+        }
+    }
+}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/PBES2Params.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/PBES2Params.cs
deleted file mode 100644 (file)
index e794374..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-// 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.Runtime.InteropServices;
-
-namespace System.Security.Cryptography.Asn1
-{
-    // https://tools.ietf.org/html/rfc2898#appendix-A.4
-    //
-    // PBES2-params ::= SEQUENCE {
-    //   keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
-    //   encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} }
-    //
-    [StructLayout(LayoutKind.Sequential)]
-    internal struct PBES2Params
-    {
-        public AlgorithmIdentifierAsn KeyDerivationFunc;
-        public AlgorithmIdentifierAsn EncryptionScheme;
-    }
-}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/PBES2Params.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/PBES2Params.xml
new file mode 100644 (file)
index 0000000..a313795
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+  xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+  name="PBES2Params"
+  namespace="System.Security.Cryptography.Asn1">
+
+  <!--
+    https://tools.ietf.org/html/rfc2898#appendix-A.4
+
+    PBES2-params ::= SEQUENCE {
+        keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
+        encryptionScheme AlgorithmIdentifier {{PBES2-Encs}}
+    }
+  -->
+  <asn:AsnType name="KeyDerivationFunc" typeName="System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn" />
+  <asn:AsnType name="EncryptionScheme" typeName="System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn" />
+</asn:Sequence>
\ No newline at end of file
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/PBES2Params.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/PBES2Params.xml.cs
new file mode 100644 (file)
index 0000000..60a15d7
--- /dev/null
@@ -0,0 +1,64 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+    [StructLayout(LayoutKind.Sequential)]
+    internal partial struct PBES2Params
+    {
+        internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn KeyDerivationFunc;
+        internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn EncryptionScheme;
+      
+        internal void Encode(AsnWriter writer)
+        {
+            Encode(writer, Asn1Tag.Sequence);
+        }
+    
+        internal void Encode(AsnWriter writer, Asn1Tag tag)
+        {
+            writer.PushSequence(tag);
+            
+            KeyDerivationFunc.Encode(writer);
+            EncryptionScheme.Encode(writer);
+            writer.PopSequence(tag);
+        }
+
+        internal static PBES2Params Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+        }
+        
+        internal static PBES2Params Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            AsnReader reader = new AsnReader(encoded, ruleSet);
+            
+            Decode(reader, expectedTag, out PBES2Params decoded);
+            reader.ThrowIfNotEmpty();
+            return decoded;
+        }
+
+        internal static void Decode(AsnReader reader, out PBES2Params decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            Decode(reader, Asn1Tag.Sequence, out decoded);
+        }
+
+        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out PBES2Params decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            decoded = default;
+            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+            
+            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(sequenceReader, out decoded.KeyDerivationFunc);
+            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(sequenceReader, out decoded.EncryptionScheme);
+
+            sequenceReader.ThrowIfNotEmpty();
+        }
+    }
+}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2Params.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2Params.cs
deleted file mode 100644 (file)
index b45e569..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-// 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.Runtime.InteropServices;
-
-namespace System.Security.Cryptography.Asn1
-{
-    // https://tools.ietf.org/html/rfc2898#appendix-A.2
-    //
-    // PBKDF2-params ::= SEQUENCE {
-    //   salt CHOICE {
-    //     specified OCTET STRING,
-    //     otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}}
-    //   },
-    //   iterationCount INTEGER (1..MAX),
-    //   keyLength INTEGER (1..MAX) OPTIONAL,
-    //   prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1
-    // }
-    [StructLayout(LayoutKind.Sequential)]
-    internal struct Pbkdf2Params
-    {
-        public Pbkdf2SaltChoice Salt;
-
-        // The spec calls out that while there's technically no limit to IterationCount,
-        // that specific platforms may have their own limits.
-        //
-        // This defines ours to uint.MaxValue (and, conveniently, not a negative number)
-        public uint IterationCount;
-
-        // The biggest value that makes sense currently is 256/8 => 32.
-        [OptionalValue]
-        public byte? KeyLength;
-
-        [DefaultValue(
-            0x30, 0x0C,
-            0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x07,
-            0x05, 0x00)]
-        public AlgorithmIdentifierAsn Prf;
-    }
-}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2Params.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2Params.xml
new file mode 100644 (file)
index 0000000..271a95a
--- /dev/null
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+  xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+  name="Pbkdf2Params"
+  namespace="System.Security.Cryptography.Asn1">
+
+  <!--
+    https://tools.ietf.org/html/rfc2898#appendix-A.2
+
+    PBKDF2-params ::= SEQUENCE {
+        salt CHOICE {
+            specified OCTET STRING,
+            otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}}
+        },
+        iterationCount INTEGER (1..MAX),
+        keyLength INTEGER (1..MAX) OPTIONAL,
+        prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1
+    }
+  -->
+  <asn:AsnType name="Salt" typeName="System.Security.Cryptography.Asn1.Pbkdf2SaltChoice" />
+  <!--
+    The spec calls out that while there's technically no limit to IterationCount,
+    that specific platforms may have their own limits. This defines ours to int.MaxValue.
+  -->
+  <asn:Integer name="IterationCount" backingType="int" />
+  <!-- The biggest value that makes sense currently is 256/8 => 32. -->
+  <asn:Integer name="KeyLength" backingType="byte" optional="true" />    
+  <asn:AsnType name="Prf" typeName="System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn" defaultDerInit="0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x07, 0x05, 0x00" />
+</asn:Sequence>
\ No newline at end of file
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2Params.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2Params.xml.cs
new file mode 100644 (file)
index 0000000..61b0236
--- /dev/null
@@ -0,0 +1,133 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+    [StructLayout(LayoutKind.Sequential)]
+    internal partial struct Pbkdf2Params
+    {
+        private static byte[] s_defaultPrf = { 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x07, 0x05, 0x00 };
+  
+        internal System.Security.Cryptography.Asn1.Pbkdf2SaltChoice Salt;
+        internal int IterationCount;
+        internal byte? KeyLength;
+        internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn Prf;
+      
+#if DEBUG  
+        static Pbkdf2Params()
+        {
+            Pbkdf2Params decoded = default;
+            AsnReader reader;
+
+            reader = new AsnReader(s_defaultPrf, AsnEncodingRules.DER);
+            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(reader, out decoded.Prf);
+            reader.ThrowIfNotEmpty();
+        }
+#endif
+        internal void Encode(AsnWriter writer)
+        {
+            Encode(writer, Asn1Tag.Sequence);
+        }
+    
+        internal void Encode(AsnWriter writer, Asn1Tag tag)
+        {
+            writer.PushSequence(tag);
+            
+            Salt.Encode(writer);
+            writer.WriteInteger(IterationCount);
+
+            if (KeyLength.HasValue)
+            {
+                writer.WriteInteger(KeyLength.Value);
+            }
+
+        
+            // DEFAULT value handler for Prf.
+            {
+                using (AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER))
+                {
+                    Prf.Encode(tmp);
+                    ReadOnlySpan<byte> encoded = tmp.EncodeAsSpan();
+
+                    if (!encoded.SequenceEqual(s_defaultPrf))
+                    {
+                        writer.WriteEncodedValue(encoded.ToArray());
+                    }
+                }
+            }
+
+            writer.PopSequence(tag);
+        }
+
+        internal static Pbkdf2Params Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+        }
+        
+        internal static Pbkdf2Params Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            AsnReader reader = new AsnReader(encoded, ruleSet);
+            
+            Decode(reader, expectedTag, out Pbkdf2Params decoded);
+            reader.ThrowIfNotEmpty();
+            return decoded;
+        }
+
+        internal static void Decode(AsnReader reader, out Pbkdf2Params decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            Decode(reader, Asn1Tag.Sequence, out decoded);
+        }
+
+        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out Pbkdf2Params decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            decoded = default;
+            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnReader defaultReader;
+            
+            System.Security.Cryptography.Asn1.Pbkdf2SaltChoice.Decode(sequenceReader, out decoded.Salt);
+
+            if (!sequenceReader.TryReadInt32(out decoded.IterationCount))
+            {
+                sequenceReader.ThrowIfNotEmpty();
+            }
+
+
+            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Integer))
+            {
+
+                if (sequenceReader.TryReadUInt8(out byte tmpKeyLength))
+                {
+                    decoded.KeyLength = tmpKeyLength;
+                }
+                else
+                {
+                    sequenceReader.ThrowIfNotEmpty();
+                }
+
+            }
+
+
+            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Sequence))
+            {
+                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(sequenceReader, out decoded.Prf);
+            }
+            else
+            {
+                defaultReader = new AsnReader(s_defaultPrf, AsnEncodingRules.DER);
+                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(defaultReader, out decoded.Prf);
+            }
+
+
+            sequenceReader.ThrowIfNotEmpty();
+        }
+    }
+}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2SaltChoice.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2SaltChoice.cs
deleted file mode 100644 (file)
index 7b0c4a5..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-// 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.Runtime.InteropServices;
-
-namespace System.Security.Cryptography.Asn1
-{
-    // https://tools.ietf.org/html/rfc2898#appendix-A.2
-    //
-    // PBKDF2-params ::= SEQUENCE {
-    //   salt CHOICE {
-    //     specified OCTET STRING,
-    //     otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}}
-    //   },
-    //   iterationCount INTEGER (1..MAX),
-    //   keyLength INTEGER (1..MAX) OPTIONAL,
-    //   prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT
-    //   algid-hmacWithSHA1
-    // }
-    [Choice]
-    [StructLayout(LayoutKind.Sequential)]
-    internal struct Pbkdf2SaltChoice
-    {
-        [OctetString]
-        public ReadOnlyMemory<byte>? Specified;
-
-        public AlgorithmIdentifierAsn? OtherSource;
-    }
-}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2SaltChoice.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2SaltChoice.xml
new file mode 100644 (file)
index 0000000..4d1e0d6
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Choice
+  xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+  name="Pbkdf2SaltChoice"
+  namespace="System.Security.Cryptography.Asn1">
+
+  <!--
+    https://tools.ietf.org/html/rfc2898#appendix-A.2
+
+    PBKDF2-params ::= SEQUENCE {
+        salt CHOICE {
+            specified OCTET STRING,
+            otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}}
+        },
+        iterationCount INTEGER (1..MAX),
+        keyLength INTEGER (1..MAX) OPTIONAL,
+        prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1
+    }
+  -->
+  <asn:OctetString name="Specified" />
+  <asn:AsnType name="OtherSource" typeName="System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn" />
+</asn:Choice>
\ No newline at end of file
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2SaltChoice.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2SaltChoice.xml.cs
new file mode 100644 (file)
index 0000000..7dc694e
--- /dev/null
@@ -0,0 +1,104 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+    [StructLayout(LayoutKind.Sequential)]
+    internal partial struct Pbkdf2SaltChoice
+    {
+        internal ReadOnlyMemory<byte>? Specified;
+        internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn? OtherSource;
+
+#if DEBUG
+        static Pbkdf2SaltChoice()
+        {
+            var usedTags = new System.Collections.Generic.Dictionary<Asn1Tag, string>();
+            Action<Asn1Tag, string> ensureUniqueTag = (tag, fieldName) =>
+            {
+                if (usedTags.TryGetValue(tag, out string existing))
+                {
+                    throw new InvalidOperationException($"Tag '{tag}' is in use by both '{existing}' and '{fieldName}'");
+                }
+
+                usedTags.Add(tag, fieldName);
+            };
+            
+            ensureUniqueTag(Asn1Tag.PrimitiveOctetString, "Specified");
+            ensureUniqueTag(Asn1Tag.Sequence, "OtherSource");
+        }
+#endif
+
+        internal void Encode(AsnWriter writer)
+        {
+            bool wroteValue = false; 
+            
+            if (Specified.HasValue)
+            {
+                if (wroteValue)
+                    throw new CryptographicException();
+                
+                writer.WriteOctetString(Specified.Value.Span);
+                wroteValue = true;
+            }
+
+            if (OtherSource.HasValue)
+            {
+                if (wroteValue)
+                    throw new CryptographicException();
+                
+                OtherSource.Value.Encode(writer);
+                wroteValue = true;
+            }
+
+            if (!wroteValue)
+            {
+                throw new CryptographicException();
+            }
+        }
+
+        internal static Pbkdf2SaltChoice Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            AsnReader reader = new AsnReader(encoded, ruleSet);
+            
+            Decode(reader, out Pbkdf2SaltChoice decoded);
+            reader.ThrowIfNotEmpty();
+            return decoded;
+        }
+
+        internal static void Decode(AsnReader reader, out Pbkdf2SaltChoice decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            decoded = default;
+            Asn1Tag tag = reader.PeekTag();
+            
+            if (tag.HasSameClassAndValue(Asn1Tag.PrimitiveOctetString))
+            {
+
+                if (reader.TryGetPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpSpecified))
+                {
+                    decoded.Specified = tmpSpecified;
+                }
+                else
+                {
+                    decoded.Specified = reader.ReadOctetString();
+                }
+
+            }
+            else if (tag.HasSameClassAndValue(Asn1Tag.Sequence))
+            {
+                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn tmpOtherSource;
+                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(reader, out tmpOtherSource);
+                decoded.OtherSource = tmpOtherSource;
+
+            }
+            else
+            {
+                throw new CryptographicException();
+            }
+        }
+    }
+}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/PrivateKeyInfoAsn.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/PrivateKeyInfoAsn.cs
deleted file mode 100644 (file)
index ab517ef..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-// 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.Runtime.InteropServices;
-
-namespace System.Security.Cryptography.Asn1
-{
-    // https://tools.ietf.org/html/rfc5208#section-5
-    //
-    // PrivateKeyInfo ::= SEQUENCE {
-    //   version                   Version,
-    //   privateKeyAlgorithm       PrivateKeyAlgorithmIdentifier,
-    //   privateKey                PrivateKey,
-    //   attributes           [0]  IMPLICIT Attributes OPTIONAL }
-    // 
-    // Version ::= INTEGER
-    // PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
-    // PrivateKey ::= OCTET STRING
-    // Attributes ::= SET OF Attribute
-    [StructLayout(LayoutKind.Sequential)]
-    internal struct PrivateKeyInfoAsn
-    {
-        public byte Version;
-
-        public AlgorithmIdentifierAsn PrivateKeyAlgorithm;
-
-        [OctetString]
-        public ReadOnlyMemory<byte> PrivateKey;
-
-        [ExpectedTag(0)]
-        [OptionalValue]
-        public AttributeAsn[] Attributes;
-
-        internal void Encode(AsnWriter writer)
-        {
-            AsnSerializer.Serialize(this, writer);
-        }
-
-        internal static void Decode(AsnReader reader, out PrivateKeyInfoAsn decoded)
-        {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            ReadOnlyMemory<byte> value = reader.GetEncodedValue();
-            decoded = AsnSerializer.Deserialize<PrivateKeyInfoAsn>(value, reader.RuleSet);
-        }
-    }
-}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/PrivateKeyInfoAsn.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/PrivateKeyInfoAsn.xml
new file mode 100644 (file)
index 0000000..830e897
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+  xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+  name="PrivateKeyInfoAsn"
+  namespace="System.Security.Cryptography.Asn1">
+
+  <!--
+    https://tools.ietf.org/html/rfc5208#section-5
+
+    PrivateKeyInfo ::= SEQUENCE {
+        version                   Version,
+        privateKeyAlgorithm       PrivateKeyAlgorithmIdentifier,
+        privateKey                PrivateKey,
+        attributes           [0]  IMPLICIT Attributes OPTIONAL
+    }
+
+    Version ::= INTEGER
+    PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
+    PrivateKey ::= OCTET STRING
+    Attributes ::= SET OF Attribute
+  -->
+  <asn:Integer name="Version" backingType="byte" />
+  <asn:AsnType name="PrivateKeyAlgorithm" typeName="System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn" />
+  <asn:OctetString name="PrivateKey" />
+  <asn:SetOf name="Attributes" implicitTag="0" optional="true">
+    <asn:AsnType typeName="System.Security.Cryptography.Asn1.AttributeAsn" />
+  </asn:SetOf>
+</asn:Sequence>
\ No newline at end of file
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/PrivateKeyInfoAsn.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/PrivateKeyInfoAsn.xml.cs
new file mode 100644 (file)
index 0000000..fd9d3b9
--- /dev/null
@@ -0,0 +1,118 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+    [StructLayout(LayoutKind.Sequential)]
+    internal partial struct PrivateKeyInfoAsn
+    {
+        internal byte Version;
+        internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn PrivateKeyAlgorithm;
+        internal ReadOnlyMemory<byte> PrivateKey;
+        internal System.Security.Cryptography.Asn1.AttributeAsn[] Attributes;
+      
+        internal void Encode(AsnWriter writer)
+        {
+            Encode(writer, Asn1Tag.Sequence);
+        }
+    
+        internal void Encode(AsnWriter writer, Asn1Tag tag)
+        {
+            writer.PushSequence(tag);
+            
+            writer.WriteInteger(Version);
+            PrivateKeyAlgorithm.Encode(writer);
+            writer.WriteOctetString(PrivateKey.Span);
+
+            if (Attributes != null)
+            {
+
+                writer.PushSetOf(new Asn1Tag(TagClass.ContextSpecific, 0));
+                for (int i = 0; i < Attributes.Length; i++)
+                {
+                    Attributes[i].Encode(writer); 
+                }
+                writer.PopSetOf(new Asn1Tag(TagClass.ContextSpecific, 0));
+
+            }
+
+            writer.PopSequence(tag);
+        }
+
+        internal static PrivateKeyInfoAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+        }
+        
+        internal static PrivateKeyInfoAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            AsnReader reader = new AsnReader(encoded, ruleSet);
+            
+            Decode(reader, expectedTag, out PrivateKeyInfoAsn decoded);
+            reader.ThrowIfNotEmpty();
+            return decoded;
+        }
+
+        internal static void Decode(AsnReader reader, out PrivateKeyInfoAsn decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            Decode(reader, Asn1Tag.Sequence, out decoded);
+        }
+
+        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out PrivateKeyInfoAsn decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            decoded = default;
+            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnReader collectionReader;
+            
+
+            if (!sequenceReader.TryReadUInt8(out decoded.Version))
+            {
+                sequenceReader.ThrowIfNotEmpty();
+            }
+
+            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(sequenceReader, out decoded.PrivateKeyAlgorithm);
+
+            if (sequenceReader.TryGetPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpPrivateKey))
+            {
+                decoded.PrivateKey = tmpPrivateKey;
+            }
+            else
+            {
+                decoded.PrivateKey = sequenceReader.ReadOctetString();
+            }
+
+
+            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
+            {
+
+                // Decode SEQUENCE OF for Attributes
+                {
+                    collectionReader = sequenceReader.ReadSetOf(new Asn1Tag(TagClass.ContextSpecific, 0));
+                    var tmpList = new List<System.Security.Cryptography.Asn1.AttributeAsn>();
+                    System.Security.Cryptography.Asn1.AttributeAsn tmpItem;
+
+                    while (collectionReader.HasData)
+                    {
+                        System.Security.Cryptography.Asn1.AttributeAsn.Decode(collectionReader, out tmpItem); 
+                        tmpList.Add(tmpItem);
+                    }
+
+                    decoded.Attributes = tmpList.ToArray();
+                }
+
+            }
+
+
+            sequenceReader.ThrowIfNotEmpty();
+        }
+    }
+}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/PssParamsAsn.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/PssParamsAsn.cs
deleted file mode 100644 (file)
index 68c0b29..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-// 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.Runtime.InteropServices;
-
-namespace System.Security.Cryptography.Asn1
-{
-    // https://tools.ietf.org/html/rfc8017#appendix-A.2.3
-    //
-    // RSASSA-PSS-params ::= SEQUENCE {
-    //   hashAlgorithm[0] HashAlgorithm      DEFAULT sha1,
-    //   maskGenAlgorithm[1] MaskGenAlgorithm DEFAULT mgf1SHA1,
-    //   saltLength[2] INTEGER            DEFAULT 20,
-    //   trailerField[3] TrailerField       DEFAULT trailerFieldBC }
-    //
-    [StructLayout(LayoutKind.Sequential)]
-    internal struct PssParamsAsn
-    {
-        // SEQUENCE(id-sha1, NULL)
-        [DefaultValue(0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00)]
-        [ExpectedTag(0, ExplicitTag = true)]
-        public AlgorithmIdentifierAsn HashAlgorithm;
-
-        // SEQUENCE(id-mgf1, SEQUENCE(id-sha1, NULL))
-        [DefaultValue(
-            0x30, 0x16, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x08, 0x30, 0x09, 0x06,
-            0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00)]
-        [ExpectedTag(1, ExplicitTag = true)]
-        public AlgorithmIdentifierAsn MaskGenAlgorithm;
-
-        [DefaultValue(0x02, 0x01, 0x14)]
-        [ExpectedTag(2, ExplicitTag = true)]
-        public uint SaltLength;
-
-        [DefaultValue(0x02, 0x01, 0x01)]
-        [ExpectedTag(3, ExplicitTag = true)]
-        public uint TrailerField;
-
-        internal void Encode(AsnWriter writer)
-        {
-            AsnSerializer.Serialize(this, writer);
-        }
-
-        internal static void Decode(AsnReader reader, out PssParamsAsn decoded)
-        {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            ReadOnlyMemory<byte> value = reader.GetEncodedValue();
-            decoded = AsnSerializer.Deserialize<PssParamsAsn>(value, reader.RuleSet);
-        }
-
-        internal static PssParamsAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
-        {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-
-            Decode(reader, out PssParamsAsn decoded);
-            reader.ThrowIfNotEmpty();
-            return decoded;
-        }
-    }
-}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/PssParamsAsn.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/PssParamsAsn.xml
new file mode 100644 (file)
index 0000000..b80c54c
--- /dev/null
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+  xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+  name="PssParamsAsn"
+  namespace="System.Security.Cryptography.Asn1">
+
+  <!--
+    https://tools.ietf.org/html/rfc8017#appendix-A.2.3
+    
+    RSASSA-PSS-params ::= SEQUENCE {
+        hashAlgorithm[0] HashAlgorithm      DEFAULT sha1,
+        maskGenAlgorithm[1] MaskGenAlgorithm DEFAULT mgf1SHA1,
+        saltLength[2] INTEGER            DEFAULT 20,
+        trailerField[3] TrailerField       DEFAULT trailerFieldBC
+    }
+  -->
+  <asn:AsnType name="HashAlgorithm" typeName="System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn" explicitTag="0" defaultDerInit="0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00" />
+  <asn:AsnType name="MaskGenAlgorithm" typeName="System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn" explicitTag="1" defaultDerInit="0x30, 0x16, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x08, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00" />
+  <asn:Integer name="SaltLength" explicitTag="2" backingType="int" defaultDerInit="0x02, 0x01, 0x14" />
+  <asn:Integer name="TrailerField" explicitTag="3" backingType="int" defaultDerInit="0x02, 0x01, 0x01" />
+</asn:Sequence>
\ No newline at end of file
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/PssParamsAsn.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/PssParamsAsn.xml.cs
new file mode 100644 (file)
index 0000000..d7e083a
--- /dev/null
@@ -0,0 +1,246 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+    [StructLayout(LayoutKind.Sequential)]
+    internal partial struct PssParamsAsn
+    {
+        private static byte[] s_defaultHashAlgorithm = { 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00 };
+  
+        private static byte[] s_defaultMaskGenAlgorithm = { 0x30, 0x16, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x08, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00 };
+  
+        private static byte[] s_defaultSaltLength = { 0x02, 0x01, 0x14 };
+  
+        private static byte[] s_defaultTrailerField = { 0x02, 0x01, 0x01 };
+  
+        internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn HashAlgorithm;
+        internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn MaskGenAlgorithm;
+        internal int SaltLength;
+        internal int TrailerField;
+      
+#if DEBUG  
+        static PssParamsAsn()
+        {
+            PssParamsAsn decoded = default;
+            AsnReader reader;
+
+            reader = new AsnReader(s_defaultHashAlgorithm, AsnEncodingRules.DER);
+            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(reader, out decoded.HashAlgorithm);
+            reader.ThrowIfNotEmpty();
+
+            reader = new AsnReader(s_defaultMaskGenAlgorithm, AsnEncodingRules.DER);
+            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(reader, out decoded.MaskGenAlgorithm);
+            reader.ThrowIfNotEmpty();
+
+            reader = new AsnReader(s_defaultSaltLength, AsnEncodingRules.DER);
+
+            if (!reader.TryReadInt32(out decoded.SaltLength))
+            {
+                reader.ThrowIfNotEmpty();
+            }
+
+            reader.ThrowIfNotEmpty();
+
+            reader = new AsnReader(s_defaultTrailerField, AsnEncodingRules.DER);
+
+            if (!reader.TryReadInt32(out decoded.TrailerField))
+            {
+                reader.ThrowIfNotEmpty();
+            }
+
+            reader.ThrowIfNotEmpty();
+        }
+#endif
+        internal void Encode(AsnWriter writer)
+        {
+            Encode(writer, Asn1Tag.Sequence);
+        }
+    
+        internal void Encode(AsnWriter writer, Asn1Tag tag)
+        {
+            writer.PushSequence(tag);
+            
+
+            // DEFAULT value handler for HashAlgorithm.
+            {
+                using (AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER))
+                {
+                    HashAlgorithm.Encode(tmp);
+                    ReadOnlySpan<byte> encoded = tmp.EncodeAsSpan();
+
+                    if (!encoded.SequenceEqual(s_defaultHashAlgorithm))
+                    {
+                        writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
+                        writer.WriteEncodedValue(encoded.ToArray());
+                        writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
+                    }
+                }
+            }
+
+
+            // DEFAULT value handler for MaskGenAlgorithm.
+            {
+                using (AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER))
+                {
+                    MaskGenAlgorithm.Encode(tmp);
+                    ReadOnlySpan<byte> encoded = tmp.EncodeAsSpan();
+
+                    if (!encoded.SequenceEqual(s_defaultMaskGenAlgorithm))
+                    {
+                        writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 1));
+                        writer.WriteEncodedValue(encoded.ToArray());
+                        writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 1));
+                    }
+                }
+            }
+
+
+            // DEFAULT value handler for SaltLength.
+            {
+                using (AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER))
+                {
+                    tmp.WriteInteger(SaltLength);
+                    ReadOnlySpan<byte> encoded = tmp.EncodeAsSpan();
+
+                    if (!encoded.SequenceEqual(s_defaultSaltLength))
+                    {
+                        writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 2));
+                        writer.WriteEncodedValue(encoded.ToArray());
+                        writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 2));
+                    }
+                }
+            }
+
+
+            // DEFAULT value handler for TrailerField.
+            {
+                using (AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER))
+                {
+                    tmp.WriteInteger(TrailerField);
+                    ReadOnlySpan<byte> encoded = tmp.EncodeAsSpan();
+
+                    if (!encoded.SequenceEqual(s_defaultTrailerField))
+                    {
+                        writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 3));
+                        writer.WriteEncodedValue(encoded.ToArray());
+                        writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 3));
+                    }
+                }
+            }
+
+            writer.PopSequence(tag);
+        }
+
+        internal static PssParamsAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+        }
+        
+        internal static PssParamsAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            AsnReader reader = new AsnReader(encoded, ruleSet);
+            
+            Decode(reader, expectedTag, out PssParamsAsn decoded);
+            reader.ThrowIfNotEmpty();
+            return decoded;
+        }
+
+        internal static void Decode(AsnReader reader, out PssParamsAsn decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            Decode(reader, Asn1Tag.Sequence, out decoded);
+        }
+
+        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out PssParamsAsn decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            decoded = default;
+            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnReader explicitReader;
+            AsnReader defaultReader;
+            
+
+            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
+            {
+                explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
+                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(explicitReader, out decoded.HashAlgorithm);
+                explicitReader.ThrowIfNotEmpty();
+            }
+            else
+            {
+                defaultReader = new AsnReader(s_defaultHashAlgorithm, AsnEncodingRules.DER);
+                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(defaultReader, out decoded.HashAlgorithm);
+            }
+
+
+            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 1)))
+            {
+                explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 1));
+                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(explicitReader, out decoded.MaskGenAlgorithm);
+                explicitReader.ThrowIfNotEmpty();
+            }
+            else
+            {
+                defaultReader = new AsnReader(s_defaultMaskGenAlgorithm, AsnEncodingRules.DER);
+                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(defaultReader, out decoded.MaskGenAlgorithm);
+            }
+
+
+            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 2)))
+            {
+                explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 2));
+
+                if (!explicitReader.TryReadInt32(out decoded.SaltLength))
+                {
+                    explicitReader.ThrowIfNotEmpty();
+                }
+
+                explicitReader.ThrowIfNotEmpty();
+            }
+            else
+            {
+                defaultReader = new AsnReader(s_defaultSaltLength, AsnEncodingRules.DER);
+
+                if (!defaultReader.TryReadInt32(out decoded.SaltLength))
+                {
+                    defaultReader.ThrowIfNotEmpty();
+                }
+
+            }
+
+
+            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 3)))
+            {
+                explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 3));
+
+                if (!explicitReader.TryReadInt32(out decoded.TrailerField))
+                {
+                    explicitReader.ThrowIfNotEmpty();
+                }
+
+                explicitReader.ThrowIfNotEmpty();
+            }
+            else
+            {
+                defaultReader = new AsnReader(s_defaultTrailerField, AsnEncodingRules.DER);
+
+                if (!defaultReader.TryReadInt32(out decoded.TrailerField))
+                {
+                    defaultReader.ThrowIfNotEmpty();
+                }
+
+            }
+
+
+            sequenceReader.ThrowIfNotEmpty();
+        }
+    }
+}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPrivateKeyAsn.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPrivateKeyAsn.xml
new file mode 100644 (file)
index 0000000..7c4f2a4
--- /dev/null
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+  xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+  name="RSAPrivateKeyAsn"
+  namespace="System.Security.Cryptography.Asn1">
+
+  <!--
+    https://tools.ietf.org/html/rfc3447#appendix-C
+
+    RSAPrivateKey ::= SEQUENCE {
+        version           Version,
+        modulus           INTEGER,  - n
+        publicExponent    INTEGER,  - e
+        privateExponent   INTEGER,  - d
+        prime1            INTEGER,  - p
+        prime2            INTEGER,  - q
+        exponent1         INTEGER,  - d mod (p-1)
+        exponent2         INTEGER,  - d mod (q-1)
+        coefficient       INTEGER,  - (inverse of q) mod p
+        otherPrimeInfos   OtherPrimeInfos OPTIONAL
+    }
+
+    Version ::= INTEGER { two-prime(0), multi(1) }
+        (CONSTRAINED BY {
+         - version must be multi if otherPrimeInfos present -
+         })
+    
+    Since we don't support otherPrimeInfos (Version=1) just don't map it in.
+  -->
+  <asn:Integer name="Version" backingType="byte" />
+  <asn:Integer name="Modulus" />
+  <asn:Integer name="PublicExponent" />
+  <asn:Integer name="PrivateExponent" />
+  <asn:Integer name="Prime1" />
+  <asn:Integer name="Prime2" />
+  <asn:Integer name="Exponent1" />
+  <asn:Integer name="Exponent2" />
+  <asn:Integer name="Coefficient" />
+</asn:Sequence>
\ No newline at end of file
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPrivateKeyAsn.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPrivateKeyAsn.xml.cs
new file mode 100644 (file)
index 0000000..9ef47af
--- /dev/null
@@ -0,0 +1,90 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+    [StructLayout(LayoutKind.Sequential)]
+    internal partial struct RSAPrivateKeyAsn
+    {
+        internal byte Version;
+        internal System.Numerics.BigInteger Modulus;
+        internal System.Numerics.BigInteger PublicExponent;
+        internal System.Numerics.BigInteger PrivateExponent;
+        internal System.Numerics.BigInteger Prime1;
+        internal System.Numerics.BigInteger Prime2;
+        internal System.Numerics.BigInteger Exponent1;
+        internal System.Numerics.BigInteger Exponent2;
+        internal System.Numerics.BigInteger Coefficient;
+      
+        internal void Encode(AsnWriter writer)
+        {
+            Encode(writer, Asn1Tag.Sequence);
+        }
+    
+        internal void Encode(AsnWriter writer, Asn1Tag tag)
+        {
+            writer.PushSequence(tag);
+            
+            writer.WriteInteger(Version);
+            writer.WriteInteger(Modulus);
+            writer.WriteInteger(PublicExponent);
+            writer.WriteInteger(PrivateExponent);
+            writer.WriteInteger(Prime1);
+            writer.WriteInteger(Prime2);
+            writer.WriteInteger(Exponent1);
+            writer.WriteInteger(Exponent2);
+            writer.WriteInteger(Coefficient);
+            writer.PopSequence(tag);
+        }
+
+        internal static RSAPrivateKeyAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+        }
+        
+        internal static RSAPrivateKeyAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            AsnReader reader = new AsnReader(encoded, ruleSet);
+            
+            Decode(reader, expectedTag, out RSAPrivateKeyAsn decoded);
+            reader.ThrowIfNotEmpty();
+            return decoded;
+        }
+
+        internal static void Decode(AsnReader reader, out RSAPrivateKeyAsn decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            Decode(reader, Asn1Tag.Sequence, out decoded);
+        }
+
+        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out RSAPrivateKeyAsn decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            decoded = default;
+            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+            
+
+            if (!sequenceReader.TryReadUInt8(out decoded.Version))
+            {
+                sequenceReader.ThrowIfNotEmpty();
+            }
+
+            decoded.Modulus = sequenceReader.GetInteger();
+            decoded.PublicExponent = sequenceReader.GetInteger();
+            decoded.PrivateExponent = sequenceReader.GetInteger();
+            decoded.Prime1 = sequenceReader.GetInteger();
+            decoded.Prime2 = sequenceReader.GetInteger();
+            decoded.Exponent1 = sequenceReader.GetInteger();
+            decoded.Exponent2 = sequenceReader.GetInteger();
+            decoded.Coefficient = sequenceReader.GetInteger();
+
+            sequenceReader.ThrowIfNotEmpty();
+        }
+    }
+}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPublicKeyAsn.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPublicKeyAsn.xml
new file mode 100644 (file)
index 0000000..42b46c4
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+  xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+  name="RSAPublicKeyAsn"
+  namespace="System.Security.Cryptography.Asn1">
+
+  <!--
+    https://tools.ietf.org/html/rfc3447#appendix-C
+
+    RSAPublicKey ::= SEQUENCE {
+        modulus           INTEGER,  - n
+        publicExponent    INTEGER   - e
+    }
+  -->
+  <asn:Integer name="Modulus" />
+  <asn:Integer name="PublicExponent" />
+</asn:Sequence>
\ No newline at end of file
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPublicKeyAsn.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPublicKeyAsn.xml.cs
new file mode 100644 (file)
index 0000000..c7c1fb1
--- /dev/null
@@ -0,0 +1,64 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+    [StructLayout(LayoutKind.Sequential)]
+    internal partial struct RSAPublicKeyAsn
+    {
+        internal System.Numerics.BigInteger Modulus;
+        internal System.Numerics.BigInteger PublicExponent;
+      
+        internal void Encode(AsnWriter writer)
+        {
+            Encode(writer, Asn1Tag.Sequence);
+        }
+    
+        internal void Encode(AsnWriter writer, Asn1Tag tag)
+        {
+            writer.PushSequence(tag);
+            
+            writer.WriteInteger(Modulus);
+            writer.WriteInteger(PublicExponent);
+            writer.PopSequence(tag);
+        }
+
+        internal static RSAPublicKeyAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+        }
+        
+        internal static RSAPublicKeyAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            AsnReader reader = new AsnReader(encoded, ruleSet);
+            
+            Decode(reader, expectedTag, out RSAPublicKeyAsn decoded);
+            reader.ThrowIfNotEmpty();
+            return decoded;
+        }
+
+        internal static void Decode(AsnReader reader, out RSAPublicKeyAsn decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            Decode(reader, Asn1Tag.Sequence, out decoded);
+        }
+
+        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out RSAPublicKeyAsn decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            decoded = default;
+            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+            
+            decoded.Modulus = sequenceReader.GetInteger();
+            decoded.PublicExponent = sequenceReader.GetInteger();
+
+            sequenceReader.ThrowIfNotEmpty();
+        }
+    }
+}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/SpecifiedECDomain.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/SpecifiedECDomain.xml
new file mode 100644 (file)
index 0000000..779f0fc
--- /dev/null
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+  xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+  name="SpecifiedECDomain"
+  namespace="System.Security.Cryptography.Asn1">
+
+  <!--
+    https://www.secg.org/sec1-v2.pdf, C.2
+
+    SpecifiedECDomain ::= SEQUENCE {
+        version SpecifiedECDomainVersion(ecdpVer1 | ecdpVer2 | ecdpVer3, ...),
+        fieldID FieldID {{FieldTypes}},
+        curve Curve,
+        base ECPoint,
+        order INTEGER,
+        cofactor INTEGER OPTIONAL,
+        hash HashAlgorithm OPTIONAL,
+        ...
+    }
+
+    HashAlgorithm ::= AlgorithmIdentifier {{ HashFunctions }}
+    ECPoint ::= OCTET STRING
+  -->
+  <asn:Integer name="Version" backingType="byte" />
+  <asn:AsnType name="FieldID" typeName="System.Security.Cryptography.Asn1.FieldID" />
+  <asn:AsnType name="Curve" typeName="System.Security.Cryptography.Asn1.CurveAsn" />
+  <asn:OctetString name="Base" />    
+  <asn:Integer name="Order" backingType="ReadOnlyMemory" />
+  <asn:Integer name="Cofactor" backingType="ReadOnlyMemory" optional="true" />
+  <asn:ObjectIdentifier name="Hash" />
+</asn:Sequence>
\ No newline at end of file
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/SpecifiedECDomain.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/SpecifiedECDomain.xml.cs
new file mode 100644 (file)
index 0000000..059c8cf
--- /dev/null
@@ -0,0 +1,103 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+    [StructLayout(LayoutKind.Sequential)]
+    internal partial struct SpecifiedECDomain
+    {
+        internal byte Version;
+        internal System.Security.Cryptography.Asn1.FieldID FieldID;
+        internal System.Security.Cryptography.Asn1.CurveAsn Curve;
+        internal ReadOnlyMemory<byte> Base;
+        internal ReadOnlyMemory<byte> Order;
+        internal ReadOnlyMemory<byte>? Cofactor;
+        internal Oid Hash;
+      
+        internal void Encode(AsnWriter writer)
+        {
+            Encode(writer, Asn1Tag.Sequence);
+        }
+    
+        internal void Encode(AsnWriter writer, Asn1Tag tag)
+        {
+            writer.PushSequence(tag);
+            
+            writer.WriteInteger(Version);
+            FieldID.Encode(writer);
+            Curve.Encode(writer);
+            writer.WriteOctetString(Base.Span);
+            writer.WriteInteger(Order.Span);
+
+            if (Cofactor.HasValue)
+            {
+                writer.WriteInteger(Cofactor.Value.Span);
+            }
+
+            writer.WriteObjectIdentifier(Hash);
+            writer.PopSequence(tag);
+        }
+
+        internal static SpecifiedECDomain Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+        }
+        
+        internal static SpecifiedECDomain Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            AsnReader reader = new AsnReader(encoded, ruleSet);
+            
+            Decode(reader, expectedTag, out SpecifiedECDomain decoded);
+            reader.ThrowIfNotEmpty();
+            return decoded;
+        }
+
+        internal static void Decode(AsnReader reader, out SpecifiedECDomain decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            Decode(reader, Asn1Tag.Sequence, out decoded);
+        }
+
+        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out SpecifiedECDomain decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            decoded = default;
+            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+            
+
+            if (!sequenceReader.TryReadUInt8(out decoded.Version))
+            {
+                sequenceReader.ThrowIfNotEmpty();
+            }
+
+            System.Security.Cryptography.Asn1.FieldID.Decode(sequenceReader, out decoded.FieldID);
+            System.Security.Cryptography.Asn1.CurveAsn.Decode(sequenceReader, out decoded.Curve);
+
+            if (sequenceReader.TryGetPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpBase))
+            {
+                decoded.Base = tmpBase;
+            }
+            else
+            {
+                decoded.Base = sequenceReader.ReadOctetString();
+            }
+
+            decoded.Order = sequenceReader.GetIntegerBytes();
+
+            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Integer))
+            {
+                decoded.Cofactor = sequenceReader.GetIntegerBytes();
+            }
+
+            decoded.Hash = sequenceReader.ReadObjectIdentifier();
+
+            sequenceReader.ThrowIfNotEmpty();
+        }
+    }
+}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/SubjectPublicKeyInfoAsn.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/SubjectPublicKeyInfoAsn.cs
deleted file mode 100644 (file)
index 63b41b9..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-// 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.Runtime.InteropServices;
-
-namespace System.Security.Cryptography.Asn1
-{
-    // https://tools.ietf.org/html/rfc3280#section-4.1
-    //
-    // SubjectPublicKeyInfo  ::=  SEQUENCE  {
-    //   algorithm            AlgorithmIdentifier,
-    //   subjectPublicKey     BIT STRING  }
-    [StructLayout(LayoutKind.Sequential)]
-    internal partial struct SubjectPublicKeyInfoAsn
-    {
-        internal AlgorithmIdentifierAsn Algorithm;
-
-        [BitString]
-        internal ReadOnlyMemory<byte> SubjectPublicKey;
-
-        internal void Encode(AsnWriter writer)
-        {
-            AsnSerializer.Serialize(this, writer);
-        }
-
-        internal static void Decode(AsnReader reader, out SubjectPublicKeyInfoAsn decoded)
-        {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            ReadOnlyMemory<byte> value = reader.GetEncodedValue();
-            decoded = AsnSerializer.Deserialize<SubjectPublicKeyInfoAsn>(value, reader.RuleSet);
-        }
-    }
-}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/SubjectPublicKeyInfoAsn.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/SubjectPublicKeyInfoAsn.xml
new file mode 100644 (file)
index 0000000..1fa5606
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+  xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+  name="SubjectPublicKeyInfoAsn"
+  namespace="System.Security.Cryptography.Asn1">
+
+  <!--
+    https://tools.ietf.org/html/rfc3280#section-4.1
+
+    SubjectPublicKeyInfo ::= SEQUENCE {
+        algorithm            AlgorithmIdentifier,
+        subjectPublicKey     BIT STRING
+    }
+  -->
+  <asn:AsnType name="Algorithm" typeName="System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn" />
+  <asn:BitString name="SubjectPublicKey" />
+</asn:Sequence>
\ No newline at end of file
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/SubjectPublicKeyInfoAsn.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/SubjectPublicKeyInfoAsn.xml.cs
new file mode 100644 (file)
index 0000000..941bf73
--- /dev/null
@@ -0,0 +1,73 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+    [StructLayout(LayoutKind.Sequential)]
+    internal partial struct SubjectPublicKeyInfoAsn
+    {
+        internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn Algorithm;
+        internal ReadOnlyMemory<byte> SubjectPublicKey;
+      
+        internal void Encode(AsnWriter writer)
+        {
+            Encode(writer, Asn1Tag.Sequence);
+        }
+    
+        internal void Encode(AsnWriter writer, Asn1Tag tag)
+        {
+            writer.PushSequence(tag);
+            
+            Algorithm.Encode(writer);
+            writer.WriteBitString(SubjectPublicKey.Span);
+            writer.PopSequence(tag);
+        }
+
+        internal static SubjectPublicKeyInfoAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+        }
+        
+        internal static SubjectPublicKeyInfoAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            AsnReader reader = new AsnReader(encoded, ruleSet);
+            
+            Decode(reader, expectedTag, out SubjectPublicKeyInfoAsn decoded);
+            reader.ThrowIfNotEmpty();
+            return decoded;
+        }
+
+        internal static void Decode(AsnReader reader, out SubjectPublicKeyInfoAsn decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            Decode(reader, Asn1Tag.Sequence, out decoded);
+        }
+
+        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out SubjectPublicKeyInfoAsn decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            decoded = default;
+            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+            
+            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(sequenceReader, out decoded.Algorithm);
+
+            if (sequenceReader.TryGetPrimitiveBitStringValue(out _, out ReadOnlyMemory<byte> tmpSubjectPublicKey))
+            {
+                decoded.SubjectPublicKey = tmpSubjectPublicKey;
+            }
+            else
+            {
+                decoded.SubjectPublicKey = sequenceReader.ReadBitString(out _);
+            }
+
+
+            sequenceReader.ThrowIfNotEmpty();
+        }
+    }
+}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/DSAKeyFormatHelper.cs b/src/libraries/Common/src/System/Security/Cryptography/DSAKeyFormatHelper.cs
new file mode 100644 (file)
index 0000000..3de051e
--- /dev/null
@@ -0,0 +1,193 @@
+// 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.Buffers;
+using System.Diagnostics;
+using System.Numerics;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography
+{
+    internal static class DSAKeyFormatHelper
+    {
+        private static readonly string[] s_validOids =
+        {
+            Oids.Dsa,
+        };
+
+        internal static void ReadDsaPrivateKey(
+            ReadOnlyMemory<byte> xBytes,
+            in AlgorithmIdentifierAsn algId,
+            out DSAParameters ret)
+        {
+            if (!algId.Parameters.HasValue)
+            {
+                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+            }
+
+            DssParms parms = DssParms.Decode(algId.Parameters.Value, AsnEncodingRules.BER);
+
+            ret = new DSAParameters
+            {
+                P = parms.P.ToByteArray(isUnsigned: true, isBigEndian: true),
+                Q = parms.Q.ToByteArray(isUnsigned: true, isBigEndian: true),
+            };
+
+            ret.G = parms.G.ExportKeyParameter(ret.P.Length);
+
+            AsnReader reader = new AsnReader(xBytes, AsnEncodingRules.DER);
+            // Force a positive interpretation because Windows sometimes writes negative numbers.
+            BigInteger x = new BigInteger(reader.GetIntegerBytes().Span, isUnsigned: true, isBigEndian: true);
+            ret.X = x.ExportKeyParameter(ret.Q.Length);
+            reader.ThrowIfNotEmpty();
+
+            // The public key is not contained within the format, calculate it.
+            BigInteger y = BigInteger.ModPow(parms.G, x, parms.P);
+            ret.Y = y.ExportKeyParameter(ret.P.Length);
+        }
+
+        internal static void ReadDsaPublicKey(
+            ReadOnlyMemory<byte> yBytes,
+            in AlgorithmIdentifierAsn algId,
+            out DSAParameters ret)
+        {
+            AsnReader reader = new AsnReader(yBytes, AsnEncodingRules.DER);
+            BigInteger y = reader.GetInteger();
+            reader.ThrowIfNotEmpty();
+
+            if (!algId.Parameters.HasValue)
+            {
+                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+            }
+
+            DssParms parms = DssParms.Decode(algId.Parameters.Value, AsnEncodingRules.BER);
+
+            ret = new DSAParameters
+            {
+                P = parms.P.ToByteArray(isUnsigned: true, isBigEndian: true),
+                Q = parms.Q.ToByteArray(isUnsigned: true, isBigEndian: true),
+            };
+
+            ret.G = parms.G.ExportKeyParameter(ret.P.Length);
+            ret.Y = y.ExportKeyParameter(ret.P.Length);
+        }
+
+        internal static void ReadSubjectPublicKeyInfo(
+            ReadOnlySpan<byte> source,
+            out int bytesRead,
+            out DSAParameters key)
+        {
+            KeyFormatHelper.ReadSubjectPublicKeyInfo<DSAParameters>(
+                s_validOids,
+                source,
+                ReadDsaPublicKey,
+                out bytesRead,
+                out key);
+        }
+
+        internal static void ReadPkcs8(
+            ReadOnlySpan<byte> source,
+            out int bytesRead,
+            out DSAParameters key)
+        {
+            KeyFormatHelper.ReadPkcs8<DSAParameters>(
+                s_validOids,
+                source,
+                ReadDsaPrivateKey,
+                out bytesRead,
+                out key);
+        }
+
+        internal static void ReadEncryptedPkcs8(
+            ReadOnlySpan<byte> source,
+            ReadOnlySpan<char> password,
+            out int bytesRead,
+            out DSAParameters key)
+        {
+            KeyFormatHelper.ReadEncryptedPkcs8<DSAParameters>(
+                s_validOids,
+                source,
+                password,
+                ReadDsaPrivateKey,
+                out bytesRead,
+                out key);
+        }
+
+        internal static void ReadEncryptedPkcs8(
+            ReadOnlySpan<byte> source,
+            ReadOnlySpan<byte> passwordBytes,
+            out int bytesRead,
+            out DSAParameters key)
+        {
+            KeyFormatHelper.ReadEncryptedPkcs8<DSAParameters>(
+                s_validOids,
+                source,
+                passwordBytes,
+                ReadDsaPrivateKey,
+                out bytesRead,
+                out key);
+        }
+
+        internal static AsnWriter WriteSubjectPublicKeyInfo(in DSAParameters dsaParameters)
+        {
+            AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
+
+            writer.PushSequence();
+            WriteAlgorithmId(writer, dsaParameters);
+            WriteKeyComponent(writer, dsaParameters.Y, bitString: true);
+            writer.PopSequence();
+
+            return writer;
+        }
+
+        internal static AsnWriter WritePkcs8(in DSAParameters dsaParameters)
+        {
+            AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
+
+            writer.PushSequence();
+            writer.WriteInteger(0);
+            WriteAlgorithmId(writer, dsaParameters);
+            WriteKeyComponent(writer, dsaParameters.X, bitString: false);
+            writer.PopSequence();
+
+            return writer;
+        }
+
+        private static void WriteAlgorithmId(AsnWriter writer, in DSAParameters dsaParameters)
+        {
+            writer.PushSequence();
+            writer.WriteObjectIdentifier(Oids.Dsa);
+
+            // Dss-Parms ::= SEQUENCE {
+            //   p INTEGER,
+            //   q INTEGER,
+            //   g INTEGER  }
+            writer.PushSequence();
+            writer.WriteKeyParameterInteger(dsaParameters.P);
+            writer.WriteKeyParameterInteger(dsaParameters.Q);
+            writer.WriteKeyParameterInteger(dsaParameters.G);
+            writer.PopSequence();
+            writer.PopSequence();
+        }
+
+        private static void WriteKeyComponent(AsnWriter writer, byte[] component, bool bitString)
+        {
+            using (AsnWriter inner = new AsnWriter(AsnEncodingRules.DER))
+            {
+                inner.WriteKeyParameterInteger(component);
+
+                if (bitString)
+                {
+                    writer.WriteBitString(inner.EncodeAsSpan());
+                }
+                else
+                {
+                    writer.WriteOctetString(inner.EncodeAsSpan());
+                }
+            }
+        }
+    }
+}
index a1d8426..f34d780 100644 (file)
@@ -4,7 +4,9 @@
 
 using System.Diagnostics;
 using System.IO;
+using System.Numerics;
 using System.Security.Cryptography.Apple;
+using System.Security.Cryptography.Asn1;
 using Internal.Cryptography;
 
 namespace System.Security.Cryptography
@@ -77,6 +79,9 @@ namespace System.Security.Cryptography
 
                 public override DSAParameters ExportParameters(bool includePrivateParameters)
                 {
+                    // Apple requires all private keys to be exported encrypted, but since we're trying to export
+                    // as parsed structures we will need to decrypt it for the user.
+                    const string ExportPassword = "DotnetExportPassphrase";
                     SecKeyPair keys = GetKeys();
 
                     if (keys.PublicKey == null ||
@@ -85,33 +90,37 @@ namespace System.Security.Cryptography
                         throw new CryptographicException(SR.Cryptography_OpenInvalidHandle);
                     }
 
-                    DSAParameters parameters = new DSAParameters();
+                    byte[] keyBlob = Interop.AppleCrypto.SecKeyExport(
+                        includePrivateParameters ? keys.PrivateKey : keys.PublicKey,
+                        exportPrivate: includePrivateParameters,
+                        password: ExportPassword);
 
-                    DerSequenceReader publicKeyReader =
-                        Interop.AppleCrypto.SecKeyExport(keys.PublicKey, exportPrivate: false);
-
-                    publicKeyReader.ReadSubjectPublicKeyInfo(ref parameters);
-
-                    if (includePrivateParameters)
+                    try
                     {
-                        DerSequenceReader privateKeyReader =
-                            Interop.AppleCrypto.SecKeyExport(keys.PrivateKey, exportPrivate: true);
-
-                        privateKeyReader.ReadPkcs8Blob(ref parameters);
+                        if (!includePrivateParameters)
+                        {
+                            DSAKeyFormatHelper.ReadSubjectPublicKeyInfo(
+                                keyBlob,
+                                out int localRead,
+                                out DSAParameters key);
+                            Debug.Assert(localRead == keyBlob.Length);
+                            return key;
+                        }
+                        else
+                        {
+                            DSAKeyFormatHelper.ReadEncryptedPkcs8(
+                                keyBlob,
+                                ExportPassword,
+                                out int localRead,
+                                out DSAParameters key);
+                            Debug.Assert(localRead == keyBlob.Length);
+                            return key;
+                        }
                     }
-
-                    KeyBlobHelpers.TrimPaddingByte(ref parameters.P);
-                    KeyBlobHelpers.TrimPaddingByte(ref parameters.Q);
-
-                    KeyBlobHelpers.PadOrTrim(ref parameters.G, parameters.P.Length);
-                    KeyBlobHelpers.PadOrTrim(ref parameters.Y, parameters.P.Length);
-
-                    if (includePrivateParameters)
+                    finally
                     {
-                        KeyBlobHelpers.PadOrTrim(ref parameters.X, parameters.Q.Length);
+                        CryptographicOperations.ZeroMemory(keyBlob);
                     }
-
-                    return parameters;
                 }
 
                 public override void ImportParameters(DSAParameters parameters)
@@ -171,7 +180,41 @@ namespace System.Security.Cryptography
                 private static SafeSecKeyRefHandle ImportKey(DSAParameters parameters)
                 {
                     bool hasPrivateKey = parameters.X != null;
-                    byte[] blob = hasPrivateKey ? parameters.ToPrivateKeyBlob() : parameters.ToSubjectPublicKeyInfo();
+                    byte[] blob;
+                    
+                    if (hasPrivateKey)
+                    {
+                        Debug.Assert(parameters.X != null);
+
+                        // DSAPrivateKey ::= SEQUENCE(
+                        //   version INTEGER,
+                        //   p INTEGER,
+                        //   q INTEGER,
+                        //   g INTEGER,
+                        //   y INTEGER,
+                        //   x INTEGER,
+                        // )
+
+                        using (AsnWriter privateKeyWriter = new AsnWriter(AsnEncodingRules.DER))
+                        {
+                            privateKeyWriter.PushSequence();
+                            privateKeyWriter.WriteInteger(0);
+                            privateKeyWriter.WriteKeyParameterInteger(parameters.P);
+                            privateKeyWriter.WriteKeyParameterInteger(parameters.Q);
+                            privateKeyWriter.WriteKeyParameterInteger(parameters.G);
+                            privateKeyWriter.WriteKeyParameterInteger(parameters.Y);
+                            privateKeyWriter.WriteKeyParameterInteger(parameters.X);
+                            privateKeyWriter.PopSequence();
+                            blob = privateKeyWriter.Encode();
+                        }
+                    }
+                    else
+                    {
+                        using (AsnWriter writer = DSAKeyFormatHelper.WriteSubjectPublicKeyInfo(parameters))
+                        {
+                            blob = writer.Encode();
+                        }
+                    }
 
                     return Interop.AppleCrypto.ImportEphemeralKey(blob, hasPrivateKey);
                 }
@@ -286,155 +329,4 @@ namespace System.Security.Cryptography
 #if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS
     }
 #endif
-
-    internal static class DsaKeyBlobHelpers
-    {
-        private static readonly Oid s_idDsa = new Oid("1.2.840.10040.4.1");
-
-        internal static void ReadSubjectPublicKeyInfo(this DerSequenceReader keyInfo, ref DSAParameters parameters)
-        {
-            // SubjectPublicKeyInfo::= SEQUENCE  {
-            //    algorithm AlgorithmIdentifier,
-            //    subjectPublicKey     BIT STRING  }
-            DerSequenceReader algorithm = keyInfo.ReadSequence();
-            string algorithmOid = algorithm.ReadOidAsString();
-
-            // EC Public Key
-            if (algorithmOid != s_idDsa.Value)
-            {
-                throw new CryptographicException();
-            }
-
-            // Dss-Parms ::= SEQUENCE {
-            //   p INTEGER,
-            //   q INTEGER,
-            //   g INTEGER
-            // }
-
-            DerSequenceReader algParameters = algorithm.ReadSequence();
-            byte[] publicKeyBlob = keyInfo.ReadBitString();
-            // We don't care about the rest of the blob here, but it's expected to not exist.
-
-            ReadSubjectPublicKeyInfo(algParameters, publicKeyBlob, ref parameters);
-        }
-
-        internal static void ReadSubjectPublicKeyInfo(
-            this DerSequenceReader algParameters,
-            byte[] publicKeyBlob,
-            ref DSAParameters parameters)
-        {
-            parameters.P = algParameters.ReadIntegerBytes();
-            parameters.Q = algParameters.ReadIntegerBytes();
-            parameters.G = algParameters.ReadIntegerBytes();
-
-            DerSequenceReader privateKeyReader = DerSequenceReader.CreateForPayload(publicKeyBlob);
-            parameters.Y = privateKeyReader.ReadIntegerBytes();
-
-            KeyBlobHelpers.TrimPaddingByte(ref parameters.P);
-            KeyBlobHelpers.TrimPaddingByte(ref parameters.Q);
-
-            KeyBlobHelpers.PadOrTrim(ref parameters.G, parameters.P.Length);
-            KeyBlobHelpers.PadOrTrim(ref parameters.Y, parameters.P.Length);
-        }
-
-        internal static byte[] ToSubjectPublicKeyInfo(this DSAParameters parameters)
-        {
-            // SubjectPublicKeyInfo::= SEQUENCE  {
-            //    algorithm AlgorithmIdentifier,
-            //    subjectPublicKey     BIT STRING  }
-
-            // Dss-Parms ::= SEQUENCE {
-            //   p INTEGER,
-            //   q INTEGER,
-            //   g INTEGER
-            // }
-
-            return DerEncoder.ConstructSequence(
-                DerEncoder.ConstructSegmentedSequence(
-                    DerEncoder.SegmentedEncodeOid(s_idDsa),
-                    DerEncoder.ConstructSegmentedSequence(
-                        DerEncoder.SegmentedEncodeUnsignedInteger(parameters.P),
-                        DerEncoder.SegmentedEncodeUnsignedInteger(parameters.Q),
-                        DerEncoder.SegmentedEncodeUnsignedInteger(parameters.G)
-                    )
-                ),
-                DerEncoder.SegmentedEncodeBitString(
-                    DerEncoder.SegmentedEncodeUnsignedInteger(parameters.Y))
-            );
-        }
-
-        internal static void ReadPkcs8Blob(this DerSequenceReader reader, ref DSAParameters parameters)
-        {
-            // Since the PKCS#8 blob for DSS/DSA does not include the public key (Y) this
-            // structure is only read after filling the public half.
-            Debug.Assert(parameters.P != null);
-            Debug.Assert(parameters.Q != null);
-            Debug.Assert(parameters.G != null);
-            Debug.Assert(parameters.Y != null);
-
-            // OneAsymmetricKey ::= SEQUENCE {
-            //   version                   Version,
-            //   privateKeyAlgorithm       PrivateKeyAlgorithmIdentifier,
-            //   privateKey                PrivateKey,
-            //   attributes            [0] Attributes OPTIONAL,
-            //   ...,
-            //   [[2: publicKey        [1] PublicKey OPTIONAL ]],
-            //   ...
-            // }
-            //
-            // PrivateKeyInfo ::= OneAsymmetricKey
-            //
-            // PrivateKey ::= OCTET STRING
-
-            int version = reader.ReadInteger();
-
-            // We understand both version 0 and 1 formats,
-            // which are now known as v1 and v2, respectively.
-            if (version > 1)
-            {
-                throw new CryptographicException();
-            }
-
-            {
-                // Ensure we're reading DSA, extract the parameters
-                DerSequenceReader algorithm = reader.ReadSequence();
-
-                string algorithmOid = algorithm.ReadOidAsString();
-
-                if (algorithmOid != s_idDsa.Value)
-                {
-                    throw new CryptographicException();
-                }
-
-                // The Dss-Params SEQUENCE is present here, but not needed since
-                // we got it from the public key already.
-            }
-
-            byte[] privateKeyBlob = reader.ReadOctetString();
-            DerSequenceReader privateKeyReader = DerSequenceReader.CreateForPayload(privateKeyBlob);
-            parameters.X = privateKeyReader.ReadIntegerBytes();
-        }
-
-        internal static byte[] ToPrivateKeyBlob(this DSAParameters parameters)
-        {
-            Debug.Assert(parameters.X != null);
-
-            // DSAPrivateKey ::= SEQUENCE(
-            //   version INTEGER,
-            //   p INTEGER,
-            //   q INTEGER,
-            //   g INTEGER,
-            //   y INTEGER,
-            //   x INTEGER,
-            // )
-
-            return DerEncoder.ConstructSequence(
-                DerEncoder.SegmentedEncodeUnsignedInteger(new byte[] { 0 }),
-                DerEncoder.SegmentedEncodeUnsignedInteger(parameters.P),
-                DerEncoder.SegmentedEncodeUnsignedInteger(parameters.Q),
-                DerEncoder.SegmentedEncodeUnsignedInteger(parameters.G),
-                DerEncoder.SegmentedEncodeUnsignedInteger(parameters.Y),
-                DerEncoder.SegmentedEncodeUnsignedInteger(parameters.X));
-        }
-    }
 }
index 9b57522..5728264 100644 (file)
@@ -267,7 +267,7 @@ namespace System.Security.Cryptography
                         throw new ObjectDisposedException(typeof(ECDiffieHellmanSecurityTransformsPublicKey).Name);
                     }
 
-                    return _ecc.ExportParameters(includePrivateParameters: false, keySizeInBIts: -1);
+                    return _ecc.ExportParameters(includePrivateParameters: false, keySizeInBits: -1);
                 }
 
                 internal SafeSecKeyRefHandle KeyHandle
diff --git a/src/libraries/Common/src/System/Security/Cryptography/EccKeyFormatHelper.cs b/src/libraries/Common/src/System/Security/Cryptography/EccKeyFormatHelper.cs
new file mode 100644 (file)
index 0000000..04463b7
--- /dev/null
@@ -0,0 +1,433 @@
+// 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.Buffers;
+using System.Diagnostics;
+using System.Numerics;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography
+{
+    internal static class EccKeyFormatHelper
+    {
+        private static readonly string[] s_validOids =
+        {
+            Oids.EcPublicKey,
+        };
+
+        internal static void ReadSubjectPublicKeyInfo(
+            ReadOnlySpan<byte> source,
+            out int bytesRead,
+            out ECParameters key)
+        {
+            KeyFormatHelper.ReadSubjectPublicKeyInfo<ECParameters>(
+                s_validOids,
+                source,
+                FromECPublicKey,
+                out bytesRead,
+                out key);
+        }
+
+        internal static void ReadEncryptedPkcs8(
+            ReadOnlySpan<byte> source,
+            ReadOnlySpan<char> password,
+            out int bytesRead,
+            out ECParameters key)
+        {
+            KeyFormatHelper.ReadEncryptedPkcs8<ECParameters>(
+                s_validOids,
+                source,
+                password,
+                FromECPrivateKey,
+                out bytesRead,
+                out key);
+        }
+
+        internal static void ReadEncryptedPkcs8(
+            ReadOnlySpan<byte> source,
+            ReadOnlySpan<byte> passwordBytes,
+            out int bytesRead,
+            out ECParameters key)
+        {
+            KeyFormatHelper.ReadEncryptedPkcs8<ECParameters>(
+                s_validOids,
+                source,
+                passwordBytes,
+                FromECPrivateKey,
+                out bytesRead,
+                out key);
+        }
+
+        internal static unsafe ECParameters FromECPrivateKey(ReadOnlySpan<byte> key, out int bytesRead)
+        {
+            fixed (byte* ptr = &MemoryMarshal.GetReference(key))
+            {
+                using (MemoryManager<byte> manager = new PointerMemoryManager<byte>(ptr, key.Length))
+                {
+                    AsnReader reader = new AsnReader(manager.Memory, AsnEncodingRules.BER);
+                    AlgorithmIdentifierAsn algId = default;
+                    ReadOnlyMemory<byte> firstValue = reader.PeekEncodedValue();
+                    FromECPrivateKey(firstValue, algId, out ECParameters ret);
+                    bytesRead = firstValue.Length;
+                    return ret;
+                }
+            }
+        }
+
+        internal static void FromECPrivateKey(
+            ReadOnlyMemory<byte> keyData,
+            in AlgorithmIdentifierAsn algId,
+            out ECParameters ret)
+        {
+            ECPrivateKey key = ECPrivateKey.Decode(keyData, AsnEncodingRules.BER);
+
+            ValidateParameters(key.Parameters, algId);
+
+            if (key.Version != 1)
+            {
+                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+            }
+
+            // Implementation limitation
+            if (key.PublicKey == null)
+            {
+                throw new CryptographicException(SR.Cryptography_NotValidPublicOrPrivateKey);
+            }
+
+            ReadOnlySpan<byte> publicKeyBytes = key.PublicKey.Value.Span;
+
+            if (publicKeyBytes.Length == 0)
+            {
+                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+            }
+
+            // Implementation limitation
+            // 04 (Uncompressed ECPoint) is almost always used.
+            if (publicKeyBytes[0] != 0x04)
+            {
+                throw new CryptographicException(SR.Cryptography_NotValidPublicOrPrivateKey);
+            }
+
+            // https://www.secg.org/sec1-v2.pdf, 2.3.4, #3 (M has length 2 * CEIL(log2(q)/8) + 1)
+            if (publicKeyBytes.Length != 2 * key.PrivateKey.Length + 1)
+            {
+                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+            }
+
+            ECDomainParameters domainParameters;
+
+            if (key.Parameters != null)
+            {
+                domainParameters = key.Parameters.Value;
+            }
+            else
+            {
+                domainParameters = ECDomainParameters.Decode(algId.Parameters.Value, AsnEncodingRules.DER);
+            }
+
+            ret = new ECParameters
+            {
+                Curve = GetCurve(domainParameters),
+                Q =
+                {
+                    X = publicKeyBytes.Slice(1, key.PrivateKey.Length).ToArray(),
+                    Y = publicKeyBytes.Slice(1 + key.PrivateKey.Length).ToArray(),
+                },
+                D = key.PrivateKey.ToArray(),
+            };
+
+            ret.Validate();
+        }
+
+        internal static void FromECPublicKey(
+            ReadOnlyMemory<byte> key,
+            in AlgorithmIdentifierAsn algId,
+            out ECParameters ret)
+        {
+            if (algId.Parameters == null)
+            {
+                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+            }
+
+            ReadOnlySpan<byte> publicKeyBytes = key.Span;
+
+            if (publicKeyBytes.Length == 0)
+            {
+                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+            }
+
+            // Implementation limitation.
+            // 04 (Uncompressed ECPoint) is almost always used.
+            if (publicKeyBytes[0] != 0x04)
+            {
+                throw new CryptographicException(SR.Cryptography_NotValidPublicOrPrivateKey);
+            }
+
+            // https://www.secg.org/sec1-v2.pdf, 2.3.4, #3 (M has length 2 * CEIL(log2(q)/8) + 1)
+            if ((publicKeyBytes.Length & 0x01) != 1)
+            {
+                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+            }
+
+            int fieldWidth = publicKeyBytes.Length / 2;
+
+            ECDomainParameters domainParameters = ECDomainParameters.Decode(
+                algId.Parameters.Value,
+                AsnEncodingRules.DER);
+
+            ret = new ECParameters
+            {
+                Curve = GetCurve(domainParameters),
+                Q =
+                {
+                    X = publicKeyBytes.Slice(1, fieldWidth).ToArray(),
+                    Y = publicKeyBytes.Slice(1 + fieldWidth).ToArray(),
+                },
+            };
+
+            ret.Validate();
+        }
+
+        private static void ValidateParameters(ECDomainParameters? keyParameters, in AlgorithmIdentifierAsn algId)
+        {
+            // At least one is required
+            if (keyParameters == null && algId.Parameters == null)
+            {
+                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+            }
+
+            // If they are both specified they must match.
+            if (keyParameters != null && algId.Parameters != null)
+            {
+                ReadOnlySpan<byte> algIdParameters = algId.Parameters.Value.Span;
+                byte[] verify = ArrayPool<byte>.Shared.Rent(algIdParameters.Length);
+
+                try
+                {
+                    // X.509 SubjectPublicKeyInfo specifies DER encoding.
+                    // RFC 5915 specifies DER encoding for EC Private Keys.
+                    // So we can compare as DER.
+                    using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER))
+                    {
+                        keyParameters.Value.Encode(writer);
+                        if (!writer.TryEncode(verify, out int written) ||
+                            written != algIdParameters.Length ||
+                            !algIdParameters.SequenceEqual(verify.AsSpan(0, written)))
+                        {
+                            throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+                        }
+                    }
+                }
+                finally
+                {
+                    // verify contains public information and does not need to be cleared.
+                    ArrayPool<byte>.Shared.Return(verify);
+                }
+            }
+        }
+
+        private static ECCurve GetCurve(in ECDomainParameters domainParameters)
+        {
+            if (domainParameters.Named == null)
+            {
+                throw new CryptographicException(SR.Cryptography_ECC_NamedCurvesOnly);
+            }
+
+            Oid curveOid = domainParameters.Named;
+
+            switch (curveOid.Value)
+            {
+                case Oids.secp256r1:
+                    curveOid = new Oid(Oids.secp256r1, nameof(ECCurve.NamedCurves.nistP256));
+                    break;
+                case Oids.secp384r1:
+                    curveOid = new Oid(Oids.secp384r1, nameof(ECCurve.NamedCurves.nistP384));
+                    break;
+                case Oids.secp521r1:
+                    curveOid = new Oid(Oids.secp521r1, nameof(ECCurve.NamedCurves.nistP521));
+                    break;
+            }
+
+            return ECCurve.CreateFromOid(curveOid);
+        }
+
+        internal static AsnWriter WriteSubjectPublicKeyInfo(in ECParameters ecParameters)
+        {
+            ecParameters.Validate();
+
+            if (!ecParameters.Curve.IsNamed)
+            {
+                throw new CryptographicException(SR.Cryptography_ECC_NamedCurvesOnly);
+            }
+
+            // Since the public key format for EC keys is not ASN.1,
+            // write the SPKI structure manually.
+
+            AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
+
+            // SubjectPublicKeyInfo
+            writer.PushSequence();
+
+            // algorithm
+            WriteAlgorithmIdentifier(ecParameters, writer);
+
+            // subjectPublicKey
+            WriteUncompressedPublicKey(ecParameters, writer);
+
+            writer.PopSequence();
+            return writer;
+        }
+
+        private static AsnWriter WriteAlgorithmIdentifier(in ECParameters ecParameters)
+        {
+            AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
+            WriteAlgorithmIdentifier(ecParameters, writer);
+            return writer;
+        }
+
+        private static void WriteAlgorithmIdentifier(in ECParameters ecParameters, AsnWriter writer)
+        {
+            writer.PushSequence();
+
+            writer.WriteObjectIdentifier(Oids.EcPublicKey);
+            WriteEcParameters(ecParameters, writer);
+
+            writer.PopSequence();
+        }
+        internal static AsnWriter WritePkcs8PrivateKey(in ECParameters ecParameters)
+        {
+            ecParameters.Validate();
+
+            if (ecParameters.D == null)
+            {
+                throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey);
+            }
+
+            if (!ecParameters.Curve.IsNamed)
+            {
+                throw new CryptographicException(SR.Cryptography_ECC_NamedCurvesOnly);
+            }
+
+            // Don't need the domain parameters because they're contained in the algId.
+            using (AsnWriter ecPrivateKey = WriteEcPrivateKey(ecParameters, includeDomainParameters: false))
+            using (AsnWriter algorithmIdentifier = WriteAlgorithmIdentifier(ecParameters))
+            {
+                return KeyFormatHelper.WritePkcs8(algorithmIdentifier, ecPrivateKey);
+            }
+        }
+
+        private static void WriteEcParameters(in ECParameters ecParameters, AsnWriter writer)
+        {
+            if (ecParameters.Curve.IsNamed)
+            {
+                Oid oid = ecParameters.Curve.Oid;
+
+                // On Windows the FriendlyName is populated in places where the Value mightn't be.
+                if (string.IsNullOrEmpty(oid.Value))
+                {
+                    oid = Oid.FromFriendlyName(oid.FriendlyName, OidGroup.All);
+                }
+
+                writer.WriteObjectIdentifier(oid.Value);
+            }
+            else
+            {
+                throw new CryptographicException(SR.Cryptography_ECC_NamedCurvesOnly);
+            }
+        }
+
+        private static void WriteUncompressedPublicKey(in ECParameters ecParameters, AsnWriter writer)
+        {
+            int publicKeyLength = ecParameters.Q.X.Length * 2 + 1;
+            Span<byte> publicKeyBytes = stackalloc byte[0];
+            byte[] publicKeyRented = null;
+
+            if (publicKeyLength < 256)
+            {
+                publicKeyBytes = stackalloc byte[publicKeyLength];
+            }
+            else
+            {
+                publicKeyRented = ArrayPool<byte>.Shared.Rent(publicKeyLength);
+                publicKeyBytes = publicKeyRented.AsSpan(0, publicKeyLength);
+            }
+
+            try
+            {
+                publicKeyBytes[0] = 0x04;
+                ecParameters.Q.X.AsSpan().CopyTo(publicKeyBytes.Slice(1));
+                ecParameters.Q.Y.AsSpan().CopyTo(publicKeyBytes.Slice(1 + ecParameters.Q.X.Length));
+
+                writer.WriteBitString(publicKeyBytes);
+            }
+            finally
+            {
+                CryptographicOperations.ZeroMemory(publicKeyBytes);
+
+                if (publicKeyRented != null)
+                {
+                    ArrayPool<byte>.Shared.Return(publicKeyRented);
+                }
+            }
+        }
+
+        internal static AsnWriter WriteECPrivateKey(in ECParameters ecParameters)
+        {
+            return WriteEcPrivateKey(ecParameters, includeDomainParameters: true);
+        }
+
+        private static AsnWriter WriteEcPrivateKey(in ECParameters ecParameters, bool includeDomainParameters)
+        {
+            bool returning = false;
+            AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
+
+            try
+            {
+                // ECPrivateKey
+                writer.PushSequence();
+
+                // version 1
+                writer.WriteInteger(1);
+
+                // privateKey
+                writer.WriteOctetString(ecParameters.D);
+
+                // domainParameters
+                if (includeDomainParameters)
+                {
+                    Asn1Tag explicit0 = new Asn1Tag(TagClass.ContextSpecific, 0, isConstructed: true);
+                    writer.PushSequence(explicit0);
+
+                    WriteEcParameters(ecParameters, writer);
+
+                    writer.PopSequence(explicit0);
+                }
+
+                // publicKey
+                {
+                    Asn1Tag explicit1 = new Asn1Tag(TagClass.ContextSpecific, 1, isConstructed: true);
+                    writer.PushSequence(explicit1);
+
+                    WriteUncompressedPublicKey(ecParameters, writer);
+
+                    writer.PopSequence(explicit1);
+                }
+
+                writer.PopSequence();
+                returning = true;
+                return writer;
+            }
+            finally
+            {
+                if (!returning)
+                {
+                    writer.Dispose();
+                }
+            }
+        }
+    }
+}
index d914e74..2fb8d4d 100644 (file)
@@ -4,6 +4,7 @@
 
 using System.Diagnostics;
 using System.Security.Cryptography.Apple;
+using System.Security.Cryptography.Asn1;
 using Internal.Cryptography;
 
 namespace System.Security.Cryptography
@@ -87,40 +88,48 @@ namespace System.Security.Cryptography
             current?.Dispose();
         }
 
-        internal ECParameters ExportParameters(bool includePrivateParameters, int keySizeInBIts)
+        internal ECParameters ExportParameters(bool includePrivateParameters, int keySizeInBits)
         {
-            SecKeyPair keys = GetOrGenerateKeys(keySizeInBIts);
+            // Apple requires all private keys to be exported encrypted, but since we're trying to export
+            // as parsed structures we will need to decrypt it for the user.
+            const string ExportPassword = "DotnetExportPassphrase";
+            SecKeyPair keys = GetOrGenerateKeys(keySizeInBits);
 
-            SafeSecKeyRefHandle keyHandle = includePrivateParameters ? keys.PrivateKey : keys.PublicKey;
-
-            if (keyHandle == null)
-            {
+            if (keys.PublicKey == null ||
+                (includePrivateParameters && keys.PrivateKey == null))
+            { 
                 throw new CryptographicException(SR.Cryptography_OpenInvalidHandle);
             }
 
-            DerSequenceReader keyReader = Interop.AppleCrypto.SecKeyExport(keyHandle, includePrivateParameters);
-            ECParameters parameters = new ECParameters();
+            byte[] keyBlob = Interop.AppleCrypto.SecKeyExport(
+                includePrivateParameters ? keys.PrivateKey : keys.PublicKey,
+                exportPrivate: includePrivateParameters,
+                password: ExportPassword);
 
-            if (includePrivateParameters)
-            {
-                keyReader.ReadPkcs8Blob(ref parameters);
-            }
-            else
+            try
             {
-                keyReader.ReadSubjectPublicKeyInfo(ref parameters);
+                if (!includePrivateParameters)
+                {
+                    EccKeyFormatHelper.ReadSubjectPublicKeyInfo(
+                        keyBlob,
+                        out int localRead,
+                        out ECParameters key);
+                    return key;
+                }
+                else
+                {
+                    EccKeyFormatHelper.ReadEncryptedPkcs8(
+                        keyBlob,
+                        ExportPassword,
+                        out int localRead,
+                        out ECParameters key);
+                    return key;
+                }
             }
-
-            int size = AsymmetricAlgorithmHelpers.BitsToBytes(keySizeInBIts);
-
-            KeyBlobHelpers.PadOrTrim(ref parameters.Q.X, size);
-            KeyBlobHelpers.PadOrTrim(ref parameters.Q.Y, size);
-
-            if (includePrivateParameters)
+            finally
             {
-                KeyBlobHelpers.PadOrTrim(ref parameters.D, size);
+                CryptographicOperations.ZeroMemory(keyBlob);
             }
-
-            return parameters;
         }
 
         public int ImportParameters(ECParameters parameters)
@@ -176,238 +185,24 @@ namespace System.Security.Cryptography
         private static SafeSecKeyRefHandle ImportKey(ECParameters parameters)
         {
             bool isPrivateKey = parameters.D != null;
-            byte[] blob = isPrivateKey ? parameters.ToPrivateKeyBlob() : parameters.ToSubjectPublicKeyInfo();
-
-            return Interop.AppleCrypto.ImportEphemeralKey(blob, isPrivateKey);
-        }
-    }
-
-    internal static class EcKeyBlobHelpers
-    {
-        private static readonly byte[] s_version1 = { 1 };
-        private static readonly byte[][] s_encodedVersion1 = DerEncoder.SegmentedEncodeUnsignedInteger(s_version1);
-
-        private static readonly Oid s_idEcPublicKey = new Oid("1.2.840.10045.2.1", null);
-        private static readonly byte[][] s_encodedIdEcPublicKey = DerEncoder.SegmentedEncodeOid(s_idEcPublicKey);
-
-        internal static void ReadPkcs8Blob(this DerSequenceReader reader, ref ECParameters parameters)
-        {
-            // OneAsymmetricKey ::= SEQUENCE {
-            //   version                   Version,
-            //   privateKeyAlgorithm       PrivateKeyAlgorithmIdentifier,
-            //   privateKey                PrivateKey,
-            //   attributes            [0] Attributes OPTIONAL,
-            //   ...,
-            //   [[2: publicKey        [1] PublicKey OPTIONAL ]],
-            //   ...
-            // }
-            //
-            // PrivateKeyInfo ::= OneAsymmetricKey
-            //
-            // PrivateKey ::= OCTET STRING
-
-            int version = reader.ReadInteger();
-
-            // We understand both version 0 and 1 formats,
-            // which are now known as v1 and v2, respectively.
-            if (version > 1)
-            {
-                throw new CryptographicException();
-            }
+            byte[] blob;
 
+            if (isPrivateKey)
             {
-                // Ensure we're reading EC Public Key (well, Private, but the OID says Public)
-                DerSequenceReader algorithm = reader.ReadSequence();
-
-                string algorithmOid = algorithm.ReadOidAsString();
-
-                if (algorithmOid != s_idEcPublicKey.Value)
+                using (AsnWriter privateKey = EccKeyFormatHelper.WriteECPrivateKey(parameters))
                 {
-                    throw new CryptographicException();
+                    blob = privateKey.Encode();
                 }
             }
-
-            byte[] privateKeyBlob = reader.ReadOctetString();
-
-            try
+            else
             {
-                // ECPrivateKey{CURVES:IOSet} ::= SEQUENCE {
-                //   version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
-                //   privateKey OCTET STRING,
-                //   parameters [0] Parameters{{IOSet}} OPTIONAL,
-                //   publicKey  [1] BIT STRING OPTIONAL
-                // }
-                DerSequenceReader keyReader = new DerSequenceReader(privateKeyBlob);
-                version = keyReader.ReadInteger();
-
-                // We understand the version 1 format
-                if (version > 1)
+                using (AsnWriter publicKey = EccKeyFormatHelper.WriteSubjectPublicKeyInfo(parameters))
                 {
-                    throw new CryptographicException();
+                    blob = publicKey.Encode();
                 }
-
-                parameters.D = keyReader.ReadOctetString();
-
-                // Check for context specific 0
-                const byte ConstructedContextSpecific =
-                    DerSequenceReader.ContextSpecificTagFlag | DerSequenceReader.ConstructedFlag;
-
-                const byte ConstructedContextSpecific0 = (ConstructedContextSpecific | 0);
-                const byte ConstructedContextSpecific1 = (ConstructedContextSpecific | 1);
-
-                if (keyReader.PeekTag() != ConstructedContextSpecific0)
-                {
-                    throw new CryptographicException();
-                }
-
-                // Parameters ::= CHOICE {
-                //   ecParameters ECParameters,
-                //   namedCurve CURVES.&id({ CurveNames}),
-                //   implicitlyCA  NULL
-                // }
-                DerSequenceReader parametersReader = keyReader.ReadSequence();
-
-                if (parametersReader.PeekTag() != (int)DerSequenceReader.DerTag.ObjectIdentifier)
-                {
-                    throw new PlatformNotSupportedException(SR.Cryptography_ECC_NamedCurvesOnly);
-                }
-
-                parameters.Curve = ECCurve.CreateFromValue(parametersReader.ReadOidAsString());
-
-                // Check for context specific 1
-                if (keyReader.PeekTag() != ConstructedContextSpecific1)
-                {
-                    throw new CryptographicException();
-                }
-
-                keyReader = keyReader.ReadSequence();
-                byte[] encodedPoint = keyReader.ReadBitString();
-                ReadEncodedPoint(encodedPoint, ref parameters);
-
-                // We don't care about the rest of the blob here, but it's expected to not exist.
             }
-            finally
-            {
-                Array.Clear(privateKeyBlob, 0, privateKeyBlob.Length);
-            }
-        }
-
-        internal static void ReadSubjectPublicKeyInfo(this DerSequenceReader keyInfo, ref ECParameters parameters)
-        {
-            // SubjectPublicKeyInfo::= SEQUENCE  {
-            //    algorithm AlgorithmIdentifier,
-            //    subjectPublicKey     BIT STRING  }
-            DerSequenceReader algorithm = keyInfo.ReadSequence();
-            string algorithmOid = algorithm.ReadOidAsString();
-
-            // EC Public Key
-            if (algorithmOid != s_idEcPublicKey.Value)
-            {
-                throw new CryptographicException();
-            }
-
-            if (algorithm.PeekTag() != (int)DerSequenceReader.DerTag.ObjectIdentifier)
-            {
-                throw new PlatformNotSupportedException(SR.Cryptography_ECC_NamedCurvesOnly);
-            }
-
-            parameters.Curve = ECCurve.CreateFromValue(algorithm.ReadOidAsString());
-
-            byte[] encodedPoint = keyInfo.ReadBitString();
-            ReadEncodedPoint(encodedPoint, ref parameters);
-
-            // We don't care about the rest of the blob here, but it's expected to not exist.
-        }
-
-        internal static byte[] ToSubjectPublicKeyInfo(this ECParameters parameters)
-        {
-            parameters.Validate();
-
-            if (!parameters.Curve.IsNamed)
-            {
-                throw new PlatformNotSupportedException(SR.Cryptography_ECC_NamedCurvesOnly);
-            }
-
-            byte[] pointBlob = GetPointBlob(ref parameters);
-
-            return DerEncoder.ConstructSequence(
-                DerEncoder.ConstructSegmentedSequence(
-                    s_encodedIdEcPublicKey,
-                    DerEncoder.SegmentedEncodeOid(parameters.Curve.Oid)),
-                DerEncoder.SegmentedEncodeBitString(pointBlob));
-        }
 
-        private static byte[] GetPointBlob(ref ECParameters parameters)
-        {
-            byte[] pointBlob = new byte[parameters.Q.X.Length + parameters.Q.Y.Length + 1];
-
-            // Uncompressed point
-            pointBlob[0] = 0x04;
-            Buffer.BlockCopy(parameters.Q.X, 0, pointBlob, 1, parameters.Q.X.Length);
-            Buffer.BlockCopy(parameters.Q.Y, 0, pointBlob, 1 + parameters.Q.X.Length, parameters.Q.Y.Length);
-            return pointBlob;
-        }
-
-        internal static byte[] ToPrivateKeyBlob(this ECParameters parameters)
-        {
-            parameters.Validate();
-
-            if (!parameters.Curve.IsNamed)
-            {
-                throw new PlatformNotSupportedException(SR.Cryptography_ECC_NamedCurvesOnly);
-            }
-
-            byte[] pointBlob = GetPointBlob(ref parameters);
-
-            // ECPrivateKey{CURVES:IOSet} ::= SEQUENCE {
-            //   version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
-            //   privateKey OCTET STRING,
-            //   parameters [0] Parameters{{IOSet}} OPTIONAL,
-            //   publicKey  [1] BIT STRING OPTIONAL
-            // }
-            return DerEncoder.ConstructSequence(
-                s_encodedVersion1,
-                DerEncoder.SegmentedEncodeOctetString(parameters.D),
-                DerEncoder.ConstructSegmentedContextSpecificValue(
-                    0,
-                    DerEncoder.SegmentedEncodeOid(parameters.Curve.Oid)),
-                DerEncoder.ConstructSegmentedContextSpecificValue(
-                    1,
-                    DerEncoder.SegmentedEncodeBitString(pointBlob)));
-        }
-
-        private static void ReadEncodedPoint(byte[] encodedPoint, ref ECParameters parameters)
-        {
-            if (encodedPoint == null || encodedPoint.Length < 1)
-            {
-                throw new CryptographicException();
-            }
-
-            byte encoding = encodedPoint[0];
-
-            switch (encoding)
-            {
-                // Uncompressed encoding (04 xbytes ybytes)
-                case 0x04:
-                // Hybrid encoding, ~yp == 0 (06 xbytes ybytes)
-                case 0x06:
-                // Hybrid encoding, ~yp == 1 (07 xbytes ybytes)
-                case 0x07:
-                    break;
-                default:
-                    Debug.Fail($"Don't know how to read point encoding {encoding}");
-                    throw new CryptographicException();
-            }
-
-            // For formats 04, 06, and 07 the X and Y points are equal length, and they should
-            // already be left-padded with zeros in cases where they're short.
-            int pointEncodingSize = (encodedPoint.Length - 1) / 2;
-            byte[] encodedX = new byte[pointEncodingSize];
-            byte[] encodedY = new byte[pointEncodingSize];
-            Buffer.BlockCopy(encodedPoint, 1, encodedX, 0, pointEncodingSize);
-            Buffer.BlockCopy(encodedPoint, 1 + pointEncodingSize, encodedY, 0, pointEncodingSize);
-            parameters.Q.X = encodedX;
-            parameters.Q.Y = encodedY;
+            return Interop.AppleCrypto.ImportEphemeralKey(blob, isPrivateKey);
         }
     }
 }
index 10bf17b..23ad0dc 100644 (file)
@@ -2,51 +2,65 @@
 // 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.Diagnostics;
+using System.Numerics;
+using System.Security.Cryptography.Asn1;
+
 namespace System.Security.Cryptography
 {
     internal static class KeyBlobHelpers
     {
-        internal static byte[] TrimPaddingByte(byte[] data)
+        internal static byte[] ExportKeyParameter(this BigInteger value, int length)
         {
-            byte[] dataLocal = data;
-            TrimPaddingByte(ref dataLocal);
-            return dataLocal;
-        }
+            byte[] target = new byte[length];
 
-        internal static void TrimPaddingByte(ref byte[] data)
-        {
-            if (data[0] != 0)
-                return;
+            if (value.TryWriteBytes(target, out int bytesWritten, isUnsigned: true, isBigEndian: true))
+            {
+                if (bytesWritten < length)
+                {
+                    Buffer.BlockCopy(target, 0, target, length - bytesWritten, bytesWritten);
+                    target.AsSpan(0, length - bytesWritten).Clear();
+                }
 
-            byte[] newData = new byte[data.Length - 1];
-            Buffer.BlockCopy(data, 1, newData, 0, newData.Length);
-            data = newData;
-        }
+                return target;
+            }
 
-        internal static byte[] PadOrTrim(byte[] data, int length)
-        {
-            byte[] dataLocal = data;
-            PadOrTrim(ref dataLocal, length);
-            return dataLocal;
+            throw new CryptographicException(SR.Cryptography_NotValidPublicOrPrivateKey);
         }
 
-        internal static void PadOrTrim(ref byte[] data, int length)
+        internal static void WriteKeyParameterInteger(this AsnWriter writer, ReadOnlySpan<byte> integer)
         {
-            if (data.Length == length)
-                return;
+            Debug.Assert(!integer.IsEmpty);
 
-            // Need to skip the sign-padding byte.
-            if (data.Length == length + 1 && data[0] == 0)
+            if (integer[0] == 0)
             {
-                TrimPaddingByte(ref data);
-                return;
-            }
+                int newStart = 1;
+
+                while (newStart < integer.Length)
+                {
+                    if (integer[newStart] >= 0x80)
+                    {
+                        newStart--;
+                        break;
+                    }
+
+                    if (integer[newStart] != 0)
+                    {
+                        break;
+                    }
 
-            int offset = length - data.Length;
+                    newStart++;
+                }
+
+                if (newStart == integer.Length)
+                {
+                    newStart--;
+                }
+
+                integer = integer.Slice(newStart);
+            }
 
-            byte[] newData = new byte[length];
-            Buffer.BlockCopy(data, 0, newData, offset, data.Length);
-            data = newData;
+            writer.WriteIntegerUnsigned(integer);
         }
     }
 }
index 11d0cec..ad81438 100644 (file)
@@ -12,12 +12,12 @@ namespace System.Security.Cryptography
 {
     internal static class KeyFormatHelper
     {
-        internal delegate void KeyReader<TRet, TParsed>(in TParsed key, in AlgorithmIdentifierAsn algId, out TRet ret);
+        internal delegate void KeyReader<TRet>(ReadOnlyMemory<byte> key, in AlgorithmIdentifierAsn algId, out TRet ret);
 
-        internal static unsafe void ReadSubjectPublicKeyInfo<TRet, TParsed>(
+        internal static unsafe void ReadSubjectPublicKeyInfo<TRet>(
             string[] validOids,
             ReadOnlySpan<byte> source,
-            KeyReader<TRet, TParsed> keyReader,
+            KeyReader<TRet> keyReader,
             out int bytesRead,
             out TRet ret)
         {
@@ -36,8 +36,9 @@ namespace System.Security.Cryptography
             out int bytesRead)
         {
             // X.509 SubjectPublicKeyInfo is described as DER.
-            SubjectPublicKeyInfoAsn spki =
-                AsnSerializer.Deserialize<SubjectPublicKeyInfoAsn>(source, AsnEncodingRules.DER, out int read);
+            AsnReader reader = new AsnReader(source, AsnEncodingRules.DER);
+            int read = reader.PeekEncodedValue().Length;
+            SubjectPublicKeyInfoAsn.Decode(reader, out SubjectPublicKeyInfoAsn spki);
 
             if (Array.IndexOf(validOids, spki.Algorithm.Algorithm.Value) < 0)
             {
@@ -48,45 +49,31 @@ namespace System.Security.Cryptography
             return spki.SubjectPublicKey;
         }
 
-        private static void ReadSubjectPublicKeyInfo<TRet, TParsed>(
+        private static void ReadSubjectPublicKeyInfo<TRet>(
             string[] validOids,
             ReadOnlyMemory<byte> source,
-            KeyReader<TRet, TParsed> keyReader,
+            KeyReader<TRet> keyReader,
             out int bytesRead,
             out TRet ret)
         {
             // X.509 SubjectPublicKeyInfo is described as DER.
-            SubjectPublicKeyInfoAsn spki =
-                AsnSerializer.Deserialize<SubjectPublicKeyInfoAsn>(source, AsnEncodingRules.DER, out int read);
+            AsnReader reader = new AsnReader(source, AsnEncodingRules.DER);
+            int read = reader.PeekEncodedValue().Length;
+            SubjectPublicKeyInfoAsn.Decode(reader, out SubjectPublicKeyInfoAsn spki);
 
             if (Array.IndexOf(validOids, spki.Algorithm.Algorithm.Value) < 0)
             {
                 throw new CryptographicException(SR.Cryptography_NotValidPublicOrPrivateKey);
             }
 
-            TParsed parsed;
-
-            if (typeof(TParsed) == typeof(ReadOnlyMemory<byte>))
-            {
-                ReadOnlyMemory<byte> tmp = spki.SubjectPublicKey;
-                parsed = (TParsed)(object)tmp;
-            }
-            else
-            {
-                // Fails if there are unconsumed bytes.
-                parsed = AsnSerializer.Deserialize<TParsed>(
-                    spki.SubjectPublicKey,
-                    AsnEncodingRules.DER);
-            }
-
-            keyReader(parsed, spki.Algorithm, out ret);
+            keyReader(spki.SubjectPublicKey, spki.Algorithm, out ret);
             bytesRead = read;
         }
 
-        internal static unsafe void ReadPkcs8<TRet, TParsed>(
+        internal static unsafe void ReadPkcs8<TRet>(
             string[] validOids,
             ReadOnlySpan<byte> source,
-            KeyReader<TRet, TParsed> keyReader,
+            KeyReader<TRet> keyReader,
             out int bytesRead,
             out TRet ret)
         {
@@ -104,8 +91,9 @@ namespace System.Security.Cryptography
             ReadOnlyMemory<byte> source,
             out int bytesRead)
         {
-            PrivateKeyInfoAsn privateKeyInfo =
-                AsnSerializer.Deserialize<PrivateKeyInfoAsn>(source, AsnEncodingRules.BER, out int read);
+            AsnReader reader = new AsnReader(source, AsnEncodingRules.BER);
+            int read = reader.PeekEncodedValue().Length;
+            PrivateKeyInfoAsn.Decode(reader, out PrivateKeyInfoAsn privateKeyInfo);
 
             if (Array.IndexOf(validOids, privateKeyInfo.PrivateKeyAlgorithm.Algorithm.Value) < 0)
             {
@@ -116,15 +104,16 @@ namespace System.Security.Cryptography
             return privateKeyInfo.PrivateKey;
         }
 
-        private static void ReadPkcs8<TRet, TParsed>(
+        private static void ReadPkcs8<TRet>(
             string[] validOids,
             ReadOnlyMemory<byte> source,
-            KeyReader<TRet, TParsed> keyReader,
+            KeyReader<TRet> keyReader,
             out int bytesRead,
             out TRet ret)
         {
-            PrivateKeyInfoAsn privateKeyInfo =
-                AsnSerializer.Deserialize<PrivateKeyInfoAsn>(source, AsnEncodingRules.BER, out int read);
+            AsnReader reader = new AsnReader(source, AsnEncodingRules.BER);
+            int read = reader.PeekEncodedValue().Length;
+            PrivateKeyInfoAsn.Decode(reader, out PrivateKeyInfoAsn privateKeyInfo);
 
             if (Array.IndexOf(validOids, privateKeyInfo.PrivateKeyAlgorithm.Algorithm.Value) < 0)
             {
@@ -132,19 +121,15 @@ namespace System.Security.Cryptography
             }
 
             // Fails if there are unconsumed bytes.
-            TParsed parsed = AsnSerializer.Deserialize<TParsed>(
-                privateKeyInfo.PrivateKey,
-                AsnEncodingRules.BER);
-
-            keyReader(parsed, privateKeyInfo.PrivateKeyAlgorithm, out ret);
+            keyReader(privateKeyInfo.PrivateKey, privateKeyInfo.PrivateKeyAlgorithm, out ret);
             bytesRead = read;
         }
 
-        internal static unsafe void ReadEncryptedPkcs8<TRet, TParsed>(
+        internal static unsafe void ReadEncryptedPkcs8<TRet>(
             string[] validOids,
             ReadOnlySpan<byte> source,
             ReadOnlySpan<char> password,
-            KeyReader<TRet, TParsed> keyReader,
+            KeyReader<TRet> keyReader,
             out int bytesRead,
             out TRet ret)
         {
@@ -157,11 +142,11 @@ namespace System.Security.Cryptography
             }
         }
 
-        internal static unsafe void ReadEncryptedPkcs8<TRet, TParsed>(
+        internal static unsafe void ReadEncryptedPkcs8<TRet>(
             string[] validOids,
             ReadOnlySpan<byte> source,
             ReadOnlySpan<byte> passwordBytes,
-            KeyReader<TRet, TParsed> keyReader,
+            KeyReader<TRet> keyReader,
             out int bytesRead,
             out TRet ret)
         {
@@ -174,17 +159,17 @@ namespace System.Security.Cryptography
             }
         }
 
-        private static void ReadEncryptedPkcs8<TRet, TParsed>(
+        private static void ReadEncryptedPkcs8<TRet>(
             string[] validOids,
             ReadOnlyMemory<byte> source,
             ReadOnlySpan<char> password,
-            KeyReader<TRet, TParsed> keyReader,
+            KeyReader<TRet> keyReader,
             out int bytesRead,
             out TRet ret)
         {
             ReadEncryptedPkcs8(
                 validOids,
-                source.Span,
+                source,
                 password,
                 ReadOnlySpan<byte>.Empty,
                 keyReader,
@@ -192,11 +177,11 @@ namespace System.Security.Cryptography
                 out ret);
         }
 
-        private static void ReadEncryptedPkcs8<TRet, TParsed>(
+        private static void ReadEncryptedPkcs8<TRet>(
             string[] validOids,
             ReadOnlyMemory<byte> source,
             ReadOnlySpan<byte> passwordBytes,
-            KeyReader<TRet, TParsed> keyReader,
+            KeyReader<TRet> keyReader,
             out int bytesRead,
             out TRet ret)
         {
@@ -210,42 +195,18 @@ namespace System.Security.Cryptography
                 out ret);
         }
 
-        private static unsafe void ReadEncryptedPkcs8<TRet, TParsed>(
-            string[] validOids,
-            ReadOnlySpan<byte> source,
-            ReadOnlySpan<char> password,
-            ReadOnlySpan<byte> passwordBytes,
-            KeyReader<TRet, TParsed> keyReader,
-            out int bytesRead,
-            out TRet ret)
-        {
-            fixed (byte* ptr = &MemoryMarshal.GetReference(source))
-            {
-                using (MemoryManager<byte> manager = new PointerMemoryManager<byte>(ptr, source.Length))
-                {
-                    ReadEncryptedPkcs8(
-                        validOids,
-                        manager.Memory,
-                        password,
-                        passwordBytes,
-                        keyReader,
-                        out bytesRead,
-                        out ret);
-                }
-            }
-        }
-
-        private static void ReadEncryptedPkcs8<TRet, TParsed>(
+        private static void ReadEncryptedPkcs8<TRet>(
             string[] validOids,
             ReadOnlyMemory<byte> source,
             ReadOnlySpan<char> password,
             ReadOnlySpan<byte> passwordBytes,
-            KeyReader<TRet, TParsed> keyReader,
+            KeyReader<TRet> keyReader,
             out int bytesRead,
             out TRet ret)
         {
-            EncryptedPrivateKeyInfoAsn epki =
-                AsnSerializer.Deserialize<EncryptedPrivateKeyInfoAsn>(source, AsnEncodingRules.BER, out int read);
+            AsnReader reader = new AsnReader(source, AsnEncodingRules.BER);
+            int read = reader.PeekEncodedValue().Length;
+            EncryptedPrivateKeyInfoAsn.Decode(reader, out EncryptedPrivateKeyInfoAsn epki);
 
             // No supported encryption algorithms produce more bytes of decryption output than there
             // were of decryption input.
@@ -472,8 +433,9 @@ namespace System.Security.Cryptography
             ReadOnlyMemory<byte> source,
             out int bytesRead)
         {
-            EncryptedPrivateKeyInfoAsn epki =
-                AsnSerializer.Deserialize<EncryptedPrivateKeyInfoAsn>(source, AsnEncodingRules.BER, out bytesRead);
+            AsnReader reader = new AsnReader(source, AsnEncodingRules.BER);
+            int localRead = reader.PeekEncodedValue().Length;
+            EncryptedPrivateKeyInfoAsn.Decode(reader, out EncryptedPrivateKeyInfoAsn epki);
 
             // No supported encryption algorithms produce more bytes of decryption output than there
             // were of decryption input.
@@ -488,6 +450,8 @@ namespace System.Security.Cryptography
                     epki.EncryptedData.Span,
                     decrypted);
 
+                bytesRead = localRead;
+
                 return new ArraySegment<byte>(decrypted, 0, decryptedBytes);
             }
             catch (CryptographicException e)
index be9234e..2242bdb 100644 (file)
@@ -487,8 +487,7 @@ namespace System.Security.Cryptography
                 throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
             }
 
-            PBES2Params pbes2Params =
-                AsnSerializer.Deserialize<PBES2Params>(algorithmParameters.Value, AsnEncodingRules.BER);
+            PBES2Params pbes2Params = PBES2Params.Decode(algorithmParameters.Value, AsnEncodingRules.BER);
 
             if (pbes2Params.KeyDerivationFunc.Algorithm.Value != Oids.Pbkdf2)
             {
@@ -678,8 +677,7 @@ namespace System.Security.Cryptography
                 throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
             }
 
-            Pbkdf2Params pbkdf2Params =
-                AsnSerializer.Deserialize<Pbkdf2Params>(parameters.Value, AsnEncodingRules.BER);
+            Pbkdf2Params pbkdf2Params = Pbkdf2Params.Decode(parameters.Value, AsnEncodingRules.BER);
 
             // No OtherSource is defined in RFC 2898 or RFC 8018, so whatever
             // algorithm was requested isn't one we know.
@@ -779,8 +777,7 @@ namespace System.Security.Cryptography
                 throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
             }
 
-            PBEParameter pbeParameters =
-                AsnSerializer.Deserialize<PBEParameter>(algorithmParameters.Value, AsnEncodingRules.BER);
+            PBEParameter pbeParameters = PBEParameter.Decode(algorithmParameters.Value, AsnEncodingRules.BER);
 
             if (pbeParameters.Salt.Length != 8)
             {
@@ -841,7 +838,7 @@ namespace System.Security.Cryptography
                 throw new CryptographicException();
             }
 
-            PBEParameter pbeParameters = AsnSerializer.Deserialize<PBEParameter>(
+            PBEParameter pbeParameters = PBEParameter.Decode(
                 algorithmIdentifier.Parameters.Value,
                 AsnEncodingRules.BER);
 
diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSAKeyFormatHelper.cs b/src/libraries/Common/src/System/Security/Cryptography/RSAKeyFormatHelper.cs
new file mode 100644 (file)
index 0000000..f46df24
--- /dev/null
@@ -0,0 +1,276 @@
+// 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.Buffers;
+using System.Diagnostics;
+using System.Numerics;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography
+{
+    internal static class RSAKeyFormatHelper
+    {
+        private static readonly string[] s_validOids =
+        {
+            Oids.Rsa,
+        };
+
+        internal static void FromPkcs1PrivateKey(
+            ReadOnlyMemory<byte> keyData,
+            in AlgorithmIdentifierAsn algId,
+            out RSAParameters ret)
+        {
+            RSAPrivateKeyAsn key = RSAPrivateKeyAsn.Decode(keyData, AsnEncodingRules.BER);
+
+            if (!algId.HasNullEquivalentParameters())
+            {
+                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+            }
+
+            const int MaxSupportedVersion = 0;
+
+            if (key.Version > MaxSupportedVersion)
+            {
+                throw new CryptographicException(
+                    SR.Format(
+                        SR.Cryptography_RSAPrivateKey_VersionTooNew,
+                        key.Version,
+                        MaxSupportedVersion));
+            }
+
+            // The modulus size determines the encoded output size of the CRT parameters.
+            byte[] n = key.Modulus.ToByteArray(isUnsigned: true, isBigEndian: true);
+            int halfModulusLength = (n.Length + 1) / 2;
+
+            ret = new RSAParameters
+            {
+                Modulus = n,
+                Exponent = key.PublicExponent.ToByteArray(isUnsigned: true, isBigEndian: true),
+                D = key.PrivateExponent.ExportKeyParameter(n.Length),
+                P = key.Prime1.ExportKeyParameter(halfModulusLength),
+                Q = key.Prime2.ExportKeyParameter(halfModulusLength),
+                DP = key.Exponent1.ExportKeyParameter(halfModulusLength),
+                DQ = key.Exponent2.ExportKeyParameter(halfModulusLength),
+                InverseQ = key.Coefficient.ExportKeyParameter(halfModulusLength),
+            };
+        }
+
+        internal static void ReadRsaPublicKey(
+            ReadOnlyMemory<byte> keyData,
+            in AlgorithmIdentifierAsn algId,
+            out RSAParameters ret)
+        {
+            RSAPublicKeyAsn key = RSAPublicKeyAsn.Decode(keyData, AsnEncodingRules.BER);
+
+            ret = new RSAParameters
+            {
+                Modulus = key.Modulus.ToByteArray(isUnsigned: true, isBigEndian: true),
+                Exponent = key.PublicExponent.ToByteArray(isUnsigned: true, isBigEndian: true),
+            };
+        }
+
+        internal static void ReadSubjectPublicKeyInfo(
+            ReadOnlySpan<byte> source,
+            out int bytesRead,
+            out RSAParameters key)
+        {
+            KeyFormatHelper.ReadSubjectPublicKeyInfo<RSAParameters>(
+                s_validOids,
+                source,
+                ReadRsaPublicKey,
+                out bytesRead,
+                out key);
+        }
+
+       internal static ReadOnlyMemory<byte> ReadSubjectPublicKeyInfo(
+            ReadOnlyMemory<byte> source,
+            out int bytesRead)
+        {
+            return KeyFormatHelper.ReadSubjectPublicKeyInfo(
+                s_validOids,
+                source,
+                out bytesRead);
+        }
+
+        public static void ReadPkcs8(
+            ReadOnlySpan<byte> source,
+            out int bytesRead,
+            out RSAParameters key)
+        {
+            KeyFormatHelper.ReadPkcs8<RSAParameters>(
+                s_validOids,
+                source,
+                FromPkcs1PrivateKey, 
+                out bytesRead,
+                out key);
+        }
+
+        internal static ReadOnlyMemory<byte> ReadPkcs8(
+            ReadOnlyMemory<byte> source,
+            out int bytesRead)
+        {
+            return KeyFormatHelper.ReadPkcs8(
+                s_validOids,
+                source,
+                out bytesRead);
+        }
+
+        internal static void ReadEncryptedPkcs8(
+            ReadOnlySpan<byte> source,
+            ReadOnlySpan<char> password,
+            out int bytesRead,
+            out RSAParameters key)
+        {
+            KeyFormatHelper.ReadEncryptedPkcs8<RSAParameters>(
+                s_validOids,
+                source,
+                password,
+                FromPkcs1PrivateKey,
+                out bytesRead,
+                out key);
+        }
+
+        internal static void ReadEncryptedPkcs8(
+            ReadOnlySpan<byte> source,
+            ReadOnlySpan<byte> passwordBytes,
+            out int bytesRead,
+            out RSAParameters key)
+        {
+            KeyFormatHelper.ReadEncryptedPkcs8<RSAParameters>(
+                s_validOids,
+                source,
+                passwordBytes,
+                FromPkcs1PrivateKey,
+                out bytesRead,
+                out key);
+        }
+
+        internal static AsnWriter WriteSubjectPublicKeyInfo(in ReadOnlySpan<byte> pkcs1PublicKey)
+        {
+            AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
+
+            try
+            {
+                writer.PushSequence();
+                WriteAlgorithmIdentifier(writer);
+                writer.WriteBitString(pkcs1PublicKey);
+                writer.PopSequence();
+            }
+            catch
+            {
+                writer.Dispose();
+                throw;
+            }
+
+            return writer;
+        }
+
+        internal static AsnWriter WriteSubjectPublicKeyInfo(in RSAParameters rsaParameters)
+        {
+            using (AsnWriter pkcs1PublicKey = WritePkcs1PublicKey(rsaParameters))
+            {
+                return WriteSubjectPublicKeyInfo(pkcs1PublicKey.EncodeAsSpan());
+            }
+        }
+
+        internal static AsnWriter WritePkcs8PrivateKey(in ReadOnlySpan<byte> pkcs1PrivateKey)
+        {
+            AsnWriter writer = new AsnWriter(AsnEncodingRules.BER);
+
+            try
+            {
+                writer.PushSequence();
+                // Version 0 format (no attributes)
+                writer.WriteInteger(0);
+                WriteAlgorithmIdentifier(writer);
+                writer.WriteOctetString(pkcs1PrivateKey);
+                writer.PopSequence();
+                return writer;
+            }
+            catch
+            {
+                writer.Dispose();
+                throw;
+            }
+        }
+
+        internal static AsnWriter WritePkcs8PrivateKey(in RSAParameters rsaParameters)
+        {
+            using (AsnWriter pkcs1PrivateKey = WritePkcs1PrivateKey(rsaParameters))
+            {
+                return WritePkcs8PrivateKey(pkcs1PrivateKey.EncodeAsSpan());
+            }
+        }
+
+        private static void WriteAlgorithmIdentifier(AsnWriter writer)
+        {
+            writer.PushSequence();
+
+            // https://tools.ietf.org/html/rfc3447#appendix-C
+            //
+            // --
+            // -- When rsaEncryption is used in an AlgorithmIdentifier the
+            // -- parameters MUST be present and MUST be NULL.
+            // --
+            writer.WriteObjectIdentifier(Oids.Rsa);
+            writer.WriteNull();
+
+            writer.PopSequence();
+        }
+
+        internal static AsnWriter WritePkcs1PublicKey(in RSAParameters rsaParameters)
+        {
+            if (rsaParameters.Modulus == null || rsaParameters.Exponent == null)
+            {
+                throw new CryptographicException(SR.Cryptography_InvalidRsaParameters);
+            }
+
+            AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
+            writer.PushSequence();
+            writer.WriteKeyParameterInteger(rsaParameters.Modulus);
+            writer.WriteKeyParameterInteger(rsaParameters.Exponent);
+            writer.PopSequence();
+
+            return writer;
+        }
+
+        internal static AsnWriter WritePkcs1PrivateKey(in RSAParameters rsaParameters)
+        {
+            if (rsaParameters.Modulus == null || rsaParameters.Exponent == null)
+            {
+                throw new CryptographicException(SR.Cryptography_InvalidRsaParameters);
+            }
+
+            if (rsaParameters.D == null ||
+                rsaParameters.P == null ||
+                rsaParameters.Q == null ||
+                rsaParameters.DP == null ||
+                rsaParameters.DQ == null ||
+                rsaParameters.InverseQ == null)
+            {
+                throw new CryptographicException(SR.Cryptography_NotValidPrivateKey);
+            }
+
+            AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
+
+            writer.PushSequence();
+
+            // Format version 0
+            writer.WriteInteger(0);
+            writer.WriteKeyParameterInteger(rsaParameters.Modulus);
+            writer.WriteKeyParameterInteger(rsaParameters.Exponent);
+            writer.WriteKeyParameterInteger(rsaParameters.D);
+            writer.WriteKeyParameterInteger(rsaParameters.P);
+            writer.WriteKeyParameterInteger(rsaParameters.Q);
+            writer.WriteKeyParameterInteger(rsaParameters.DP);
+            writer.WriteKeyParameterInteger(rsaParameters.DQ);
+            writer.WriteKeyParameterInteger(rsaParameters.InverseQ);
+
+            writer.PopSequence();
+            return writer;
+        }
+    }
+}
index 761d2bd..f598dc6 100644 (file)
@@ -5,7 +5,9 @@
 using System.Buffers;
 using System.Diagnostics;
 using System.IO;
+using System.Numerics;
 using System.Security.Cryptography.Apple;
+using System.Security.Cryptography.Asn1;
 using Internal.Cryptography;
 
 namespace System.Security.Cryptography
@@ -84,38 +86,65 @@ namespace System.Security.Cryptography
 
             public override RSAParameters ExportParameters(bool includePrivateParameters)
             {
+                // Apple requires all private keys to be exported encrypted, but since we're trying to export
+                // as parsed structures we will need to decrypt it for the user.
+                const string ExportPassword = "DotnetExportPassphrase";
                 SecKeyPair keys = GetKeys();
 
-                SafeSecKeyRefHandle keyHandle = includePrivateParameters ? keys.PrivateKey : keys.PublicKey;
-
-                if (keyHandle == null)
-                {
+                if (keys.PublicKey == null ||
+                    (includePrivateParameters && keys.PrivateKey == null))
+                { 
                     throw new CryptographicException(SR.Cryptography_OpenInvalidHandle);
                 }
 
-                DerSequenceReader keyReader = Interop.AppleCrypto.SecKeyExport(keyHandle, includePrivateParameters);
-                RSAParameters parameters = new RSAParameters();
+                byte[] keyBlob = Interop.AppleCrypto.SecKeyExport(
+                    includePrivateParameters ? keys.PrivateKey : keys.PublicKey,
+                    exportPrivate: includePrivateParameters,
+                    password: ExportPassword);
 
-                if (includePrivateParameters)
-                {
-                    keyReader.ReadPkcs8Blob(ref parameters);
-                }
-                else
+                try
                 {
-                    // When exporting a key handle opened from a certificate, it seems to
-                    // export as a PKCS#1 blob instead of an X509 SubjectPublicKeyInfo blob.
-                    // So, check for that.
-                    if (keyReader.PeekTag() == (byte)DerSequenceReader.DerTag.Integer)
+                    if (!includePrivateParameters)
                     {
-                        keyReader.ReadPkcs1PublicBlob(ref parameters);
+                        // When exporting a key handle opened from a certificate, it seems to
+                        // export as a PKCS#1 blob instead of an X509 SubjectPublicKeyInfo blob.
+                        // So, check for that.
+                        // NOTE: It doesn't affect macOS Mojave when SecCertificateCopyKey API
+                        // is used.
+                        RSAParameters key;
+
+                        AsnReader reader = new AsnReader(keyBlob, AsnEncodingRules.BER);
+                        AsnReader sequenceReader = reader.ReadSequence();
+
+                        if (sequenceReader.PeekTag().Equals(Asn1Tag.Integer))
+                        {
+                            AlgorithmIdentifierAsn ignored = default;
+                            RSAKeyFormatHelper.ReadRsaPublicKey(keyBlob, ignored, out key);
+                        }
+                        else
+                        {
+                            RSAKeyFormatHelper.ReadSubjectPublicKeyInfo(
+                                keyBlob,
+                                out int localRead,
+                                out key);
+                            Debug.Assert(localRead == keyBlob.Length);
+                        }
+                        return key;
                     }
                     else
                     {
-                        keyReader.ReadSubjectPublicKeyInfo(ref parameters);
+                        RSAKeyFormatHelper.ReadEncryptedPkcs8(
+                            keyBlob,
+                            ExportPassword,
+                            out int localRead,
+                            out RSAParameters key);
+                        return key;
                     }
                 }
-
-                return parameters;
+                finally
+                {
+                    CryptographicOperations.ZeroMemory(keyBlob);
+                }
             }
 
             public override void ImportParameters(RSAParameters parameters)
@@ -690,202 +719,28 @@ namespace System.Security.Cryptography
             private static SafeSecKeyRefHandle ImportKey(RSAParameters parameters)
             {
                 bool isPrivateKey = parameters.D != null;
-                byte[] pkcs1Blob = isPrivateKey ? parameters.ToPkcs1Blob() : parameters.ToSubjectPublicKeyInfo();
-
-                return Interop.AppleCrypto.ImportEphemeralKey(pkcs1Blob, isPrivateKey);
-            }
-        }
-
-        private static Exception HashAlgorithmNameNullOrEmpty() =>
-            new ArgumentException(SR.Cryptography_HashAlgorithmNameNullOrEmpty, "hashAlgorithm");
-    }
-
-    internal static class RsaKeyBlobHelpers
-    {
-        private const string RsaOid = "1.2.840.113549.1.1.1";
-
-        // The PKCS#1 version blob for an RSA key based on 2 primes.
-        private static readonly byte[] s_versionNumberBytes = { 0 };
+                byte[] pkcs1Blob;
 
-        // The AlgorithmIdentifier structure for RSA contains an explicit NULL, for legacy/compat reasons.
-        private static readonly byte[][] s_encodedRsaAlgorithmIdentifier =
-            DerEncoder.ConstructSegmentedSequence(
-                DerEncoder.SegmentedEncodeOid(new Oid(RsaOid)),
-                // DER:NULL (0x05 0x00)
-                new byte[][]
-                {
-                    new byte[] { (byte)DerSequenceReader.DerTag.Null },
-                    new byte[] { 0 }, 
-                    Array.Empty<byte>(),
-                });
-
-        internal static byte[] ToPkcs1Blob(this RSAParameters parameters)
-        {
-            if (parameters.Exponent == null || parameters.Modulus == null)
-                throw new CryptographicException(SR.Cryptography_InvalidRsaParameters);
-
-            if (parameters.D == null)
-            {
-                if (parameters.P != null ||
-                    parameters.DP != null ||
-                    parameters.Q != null ||
-                    parameters.DQ != null ||
-                    parameters.InverseQ != null)
+                if (isPrivateKey)
                 {
-                    throw new CryptographicException(SR.Cryptography_InvalidRsaParameters);
+                    using (AsnWriter pkcs1PrivateKey = RSAKeyFormatHelper.WritePkcs1PrivateKey(parameters))
+                    {
+                        pkcs1Blob = pkcs1PrivateKey.Encode();
+                    }
                 }
-
-                return DerEncoder.ConstructSequence(
-                    DerEncoder.SegmentedEncodeUnsignedInteger(parameters.Modulus),
-                    DerEncoder.SegmentedEncodeUnsignedInteger(parameters.Exponent));
-            }
-
-            if (parameters.P == null ||
-                parameters.DP == null ||
-                parameters.Q == null ||
-                parameters.DQ == null ||
-                parameters.InverseQ == null)
-            {
-                throw new CryptographicException(SR.Cryptography_InvalidRsaParameters);
-            }
-
-            return DerEncoder.ConstructSequence(
-                DerEncoder.SegmentedEncodeUnsignedInteger(s_versionNumberBytes),
-                DerEncoder.SegmentedEncodeUnsignedInteger(parameters.Modulus),
-                DerEncoder.SegmentedEncodeUnsignedInteger(parameters.Exponent),
-                DerEncoder.SegmentedEncodeUnsignedInteger(parameters.D),
-                DerEncoder.SegmentedEncodeUnsignedInteger(parameters.P),
-                DerEncoder.SegmentedEncodeUnsignedInteger(parameters.Q),
-                DerEncoder.SegmentedEncodeUnsignedInteger(parameters.DP),
-                DerEncoder.SegmentedEncodeUnsignedInteger(parameters.DQ),
-                DerEncoder.SegmentedEncodeUnsignedInteger(parameters.InverseQ));
-        }
-
-        internal static void ReadPkcs8Blob(this DerSequenceReader reader, ref RSAParameters parameters)
-        {
-            // OneAsymmetricKey ::= SEQUENCE {
-            //   version                   Version,
-            //   privateKeyAlgorithm       PrivateKeyAlgorithmIdentifier,
-            //   privateKey                PrivateKey,
-            //   attributes            [0] Attributes OPTIONAL,
-            //   ...,
-            //   [[2: publicKey        [1] PublicKey OPTIONAL ]],
-            //   ...
-            // }
-            //
-            // PrivateKeyInfo ::= OneAsymmetricKey
-            //
-            // PrivateKey ::= OCTET STRING
-
-            int version = reader.ReadInteger();
-
-            // We understand both version 0 and 1 formats,
-            // which are now known as v1 and v2, respectively.
-            if (version > 1)
-            {
-                throw new CryptographicException();
-            }
-
-            {
-                // Ensure we're reading RSA
-                DerSequenceReader algorithm = reader.ReadSequence();
-
-                string algorithmOid = algorithm.ReadOidAsString();
-
-                if (algorithmOid != RsaOid)
+                else
                 {
-                    throw new CryptographicException();
+                    using (AsnWriter pkcs1PublicKey = RSAKeyFormatHelper.WriteSubjectPublicKeyInfo(parameters))
+                    {
+                        pkcs1Blob = pkcs1PublicKey.Encode();
+                    }
                 }
-            }
-
-            byte[] privateKeyBytes = reader.ReadOctetString();
-            // Because this was an RSA private key, the key format is PKCS#1.
-            ReadPkcs1PrivateBlob(privateKeyBytes, ref parameters);
-
-            // We don't care about the rest of the blob here, but it's expected to not exist.
-        }
-
-        internal static byte[] ToSubjectPublicKeyInfo(this RSAParameters parameters)
-        {
-            Debug.Assert(parameters.D == null);
-
-            // SubjectPublicKeyInfo::= SEQUENCE  {
-            //    algorithm AlgorithmIdentifier,
-            //    subjectPublicKey     BIT STRING  }
-            return DerEncoder.ConstructSequence(
-                s_encodedRsaAlgorithmIdentifier,
-                DerEncoder.SegmentedEncodeBitString(
-                    parameters.ToPkcs1Blob()));
-        }
-
-        internal static void ReadSubjectPublicKeyInfo(this DerSequenceReader keyInfo, ref RSAParameters parameters)
-        {
-            // SubjectPublicKeyInfo::= SEQUENCE  {
-            //    algorithm AlgorithmIdentifier,
-            //    subjectPublicKey     BIT STRING  }
-            DerSequenceReader algorithm = keyInfo.ReadSequence();
-            string algorithmOid = algorithm.ReadOidAsString();
 
-            if (algorithmOid != RsaOid)
-            {
-                throw new CryptographicException();
+                return Interop.AppleCrypto.ImportEphemeralKey(pkcs1Blob, isPrivateKey);
             }
-
-            byte[] subjectPublicKeyBytes = keyInfo.ReadBitString();
-
-            DerSequenceReader subjectPublicKey = new DerSequenceReader(subjectPublicKeyBytes);
-            subjectPublicKey.ReadPkcs1PublicBlob(ref parameters);
-        }
-
-        internal static void ReadPkcs1PublicBlob(this DerSequenceReader subjectPublicKey, ref RSAParameters parameters)
-        {
-            parameters.Modulus = KeyBlobHelpers.TrimPaddingByte(subjectPublicKey.ReadIntegerBytes());
-            parameters.Exponent = KeyBlobHelpers.TrimPaddingByte(subjectPublicKey.ReadIntegerBytes());
-
-            if (subjectPublicKey.HasData)
-                throw new CryptographicException();
         }
 
-        private static void ReadPkcs1PrivateBlob(byte[] privateKeyBytes, ref RSAParameters parameters)
-        {
-            // RSAPrivateKey::= SEQUENCE {
-            //    version Version,
-            //    modulus           INTEGER,  --n
-            //    publicExponent INTEGER,  --e
-            //    privateExponent INTEGER,  --d
-            //    prime1 INTEGER,  --p
-            //    prime2 INTEGER,  --q
-            //    exponent1 INTEGER,  --d mod(p - 1)
-            //    exponent2 INTEGER,  --d mod(q - 1)
-            //    coefficient INTEGER,  --(inverse of q) mod p
-            //    otherPrimeInfos OtherPrimeInfos OPTIONAL
-            // }
-            DerSequenceReader privateKey = new DerSequenceReader(privateKeyBytes);
-            int version = privateKey.ReadInteger();
-
-            if (version != 0)
-            {
-                throw new CryptographicException();
-            }
-
-            parameters.Modulus = KeyBlobHelpers.TrimPaddingByte(privateKey.ReadIntegerBytes());
-            parameters.Exponent = KeyBlobHelpers.TrimPaddingByte(privateKey.ReadIntegerBytes());
-
-            int modulusLen = parameters.Modulus.Length;
-            // Add one so that odd byte-length values (RSA 1032) get padded correctly.
-            int halfModulus = (modulusLen + 1) / 2;
-
-            parameters.D = KeyBlobHelpers.PadOrTrim(privateKey.ReadIntegerBytes(), modulusLen);
-            parameters.P = KeyBlobHelpers.PadOrTrim(privateKey.ReadIntegerBytes(), halfModulus);
-            parameters.Q = KeyBlobHelpers.PadOrTrim(privateKey.ReadIntegerBytes(), halfModulus);
-            parameters.DP = KeyBlobHelpers.PadOrTrim(privateKey.ReadIntegerBytes(), halfModulus);
-            parameters.DQ = KeyBlobHelpers.PadOrTrim(privateKey.ReadIntegerBytes(), halfModulus);
-            parameters.InverseQ = KeyBlobHelpers.PadOrTrim(privateKey.ReadIntegerBytes(), halfModulus);
-
-            if (privateKey.HasData)
-            {
-                throw new CryptographicException();
-            }
-        }
+        private static Exception HashAlgorithmNameNullOrEmpty() =>
+            new ArgumentException(SR.Cryptography_HashAlgorithmNameNullOrEmpty, "hashAlgorithm");
     }
 }
index 6d0a14a..c502aa4 100644 (file)
@@ -87,58 +87,5 @@ namespace Internal.Cryptography
             dest[2] = (byte)((value & 0xFF00) >> 8);
             dest[3] = (byte)(value & 0xFF);
         }
-
-        internal static byte[] ExportKeyParameter(this BigInteger value, int length)
-        {
-            byte[] target = new byte[length];
-
-            if (value.TryWriteBytes(target, out int bytesWritten, isUnsigned: true, isBigEndian: true))
-            {
-                if (bytesWritten < length)
-                {
-                    Buffer.BlockCopy(target, 0, target, length - bytesWritten, bytesWritten);
-                    target.AsSpan(0, length - bytesWritten).Clear();
-                }
-
-                return target;
-            }
-
-            throw new CryptographicException(SR.Cryptography_NotValidPublicOrPrivateKey);
-        }
-
-        internal static void WriteKeyParameterInteger(this AsnWriter writer, ReadOnlySpan<byte> integer)
-        {
-            Debug.Assert(!integer.IsEmpty);
-
-            if (integer[0] == 0)
-            {
-                int newStart = 1;
-
-                while (newStart < integer.Length)
-                {
-                    if (integer[newStart] >= 0x80)
-                    {
-                        newStart--;
-                        break;
-                    }
-
-                    if (integer[newStart] != 0)
-                    {
-                        break;
-                    }
-
-                    newStart++;
-                }
-
-                if (newStart == integer.Length)
-                {
-                    newStart--;
-                }
-
-                integer = integer.Slice(newStart);
-            }
-
-            writer.WriteIntegerUnsigned(integer);
-        }
     }
 }
index d0a30ef..440126a 100644 (file)
   <data name="Cryptography_Asn_UnusedBitCountRange" xml:space="preserve">
     <value>Unused bit count must be between 0 and 7, inclusive.</value>
   </data>
-  <data name="Cryptography_AsnSerializer_AmbiguousFieldType" xml:space="preserve">
-    <value>Field '{0}' of type '{1}' has ambiguous type '{2}', an attribute derived from AsnTypeAttribute is required.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_Choice_AllowNullNonNullable" xml:space="preserve">
-    <value>[Choice].AllowNull=true is not valid because type '{0}' cannot have a null value.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_Choice_ConflictingTagMapping" xml:space="preserve">
-    <value>The tag ({0} {1}) for field '{2}' on type '{3}' already is associated in this context with field '{4}' on type '{5}'.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_Choice_DefaultValueDisallowed" xml:space="preserve">
-    <value>Field '{0}' on [Choice] type '{1}' has a default value, which is not permitted.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_Choice_NoChoiceWasMade" xml:space="preserve">
-    <value>An instance of [Choice] type '{0}' has no non-null fields.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_Choice_NonNullableField" xml:space="preserve">
-    <value>Field '{0}' on [Choice] type '{1}' can not be assigned a null value.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_Choice_TooManyValues" xml:space="preserve">
-    <value>Fields '{0}' and '{1}' on type '{2}' are both non-null when only one value is permitted.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_Choice_TypeCycle" xml:space="preserve">
-    <value>Field '{0}' on [Choice] type '{1}' has introduced a type chain cycle.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_MultipleAsnTypeAttributes" xml:space="preserve">
-    <value>Field '{0}' on type '{1}' has multiple attributes deriving from '{2}' when at most one is permitted.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_NoJaggedArrays" xml:space="preserve">
-    <value>Type '{0}' cannot be serialized or deserialized because it is an array of arrays.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_NoMultiDimensionalArrays" xml:space="preserve">
-    <value>Type '{0}' cannot be serialized or deserialized because it is a multi-dimensional array.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_NoOpenTypes" xml:space="preserve">
-    <value>Type '{0}' cannot be serialized or deserialized because it is not sealed or has unbound generic parameters.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_Optional_NonNullableField" xml:space="preserve">
-    <value>Field '{0}' on type '{1}' is declared [OptionalValue], but it can not be assigned a null value.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_PopulateFriendlyNameOnString" xml:space="preserve">
-    <value>Field '{0}' on type '{1}' has [ObjectIdentifier].PopulateFriendlyName set to true, which is not applicable to a string.  Change the field to '{2}' or set PopulateFriendlyName to false.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_SetValueException" xml:space="preserve">
-    <value>Unable to set field {0} on type {1}.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_SpecificTagChoice" xml:space="preserve">
-    <value>Field '{0}' on type '{1}' has specified an implicit tag value via [ExpectedTag] for [Choice] type '{2}'. ExplicitTag must be true, or the [ExpectedTag] attribute removed.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_UnexpectedTypeForAttribute" xml:space="preserve">
-    <value>Field '{0}' of type '{1}' has an effective type of '{2}' when one of ({3}) was expected.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_UtcTimeTwoDigitYearMaxTooSmall" xml:space="preserve">
-    <value>Field '{0}' on type '{1}' has a [UtcTime] TwoDigitYearMax value ({2}) smaller than the minimum (99).</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_UnhandledType" xml:space="preserve">
-    <value>Could not determine how to serialize or deserialize type '{0}'.</value>
-  </data>
   <data name="Cryptography_AsnWriter_EncodeUnbalancedStack" xml:space="preserve">
     <value>Encode cannot be called while a Sequence or SetOf is still open.</value>
   </data>
index 3432105..c995678 100644 (file)
@@ -6,6 +6,7 @@
     <NoWarn>CS3016;CA5351;$(NoWarn)</NoWarn>
     <Configurations>netcoreapp-OSX-Debug;netcoreapp-OSX-Release;netcoreapp-Unix-Debug;netcoreapp-Unix-Release;netcoreapp-Windows_NT-Debug;netcoreapp-Windows_NT-Release;uap-Windows_NT-Debug;uap-Windows_NT-Release</Configurations>
   </PropertyGroup>
+  <Import Project="$(CommonPath)\System\Security\Cryptography\Asn1\AsnXml.targets"/>
   <ItemGroup>
     <Compile Include="Internal\Cryptography\AesImplementation.cs" />
     <Compile Include="Internal\Cryptography\DesImplementation.cs" />
     <Compile Include="System\Security\Cryptography\AsymmetricKeyExchangeFormatter.cs" />
     <Compile Include="System\Security\Cryptography\AsymmetricSignatureDeformatter.cs" />
     <Compile Include="System\Security\Cryptography\AsymmetricSignatureFormatter.cs" />
-    <Compile Include="System\Security\Cryptography\Asn1\CurveAsn.cs" />
-    <Compile Include="System\Security\Cryptography\Asn1\DSSParms.cs" />
-    <Compile Include="System\Security\Cryptography\Asn1\DsaPrivateKeyAsn.cs" />
-    <Compile Include="System\Security\Cryptography\Asn1\ECDomainParameters.cs" />
-    <Compile Include="System\Security\Cryptography\Asn1\ECPrivateKey.cs" />
-    <Compile Include="System\Security\Cryptography\Asn1\FieldID.cs" />
-    <Compile Include="System\Security\Cryptography\Asn1\RSAPrivateKeyAsn.cs" />
-    <Compile Include="System\Security\Cryptography\Asn1\RSAPublicKeyAsn.cs" />
-    <Compile Include="System\Security\Cryptography\Asn1\SpecifiedECDomain.cs" />
     <Compile Include="System\Security\Cryptography\CryptoConfig.cs" />
     <Compile Include="System\Security\Cryptography\DeriveBytes.cs" />
     <Compile Include="System\Security\Cryptography\DES.cs" />
     <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1V2.cs">
       <Link>Common\System\Security\Cryptography\Asn1V2.cs</Link>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1V2.Serializer.cs">
-      <Link>Common\System\Security\Cryptography\Asn1V2.Serializer.cs</Link>
-    </Compile>
     <Compile Include="$(CommonPath)\System\Security\Cryptography\AsnReader.cs">
       <Link>Common\System\Security\Cryptography\AsnReader.cs</Link>
     </Compile>
     <Compile Include="$(CommonPath)\System\Security\Cryptography\AsnWriter.cs">
       <Link>Common\System\Security\Cryptography\AsnWriter.cs</Link>
     </Compile>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\DSAKeyFormatHelper.cs">
+      <Link>Common\System\Security\Cryptography\DSAKeyFormatHelper.cs</Link>
+    </Compile>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\EccKeyFormatHelper.cs">
+      <Link>Common\System\Security\Cryptography\EccKeyFormatHelper.cs</Link>
+    </Compile>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\KeyBlobHelpers.cs">
+      <Link>Common\System\Security\Cryptography\KeyBlobHelpers.cs</Link>
+    </Compile>
     <Compile Include="$(CommonPath)\System\Security\Cryptography\KeyFormatHelper.cs">
       <Link>Common\System\Security\Cryptography\KeyFormatHelper.cs</Link>
     </Compile>
     <Compile Include="$(CommonPath)\System\Security\Cryptography\Pkcs12Kdf.cs">
       <Link>Common\System\Security\Cryptography\Pkcs12Kdf.cs</Link>
     </Compile>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\RSAKeyFormatHelper.cs">
+      <Link>Common\System\Security\Cryptography\RSAKeyFormatHelper.cs</Link>
+    </Compile>
     <Compile Include="$(CommonPath)\System\Security\Cryptography\RsaPaddingProcessor.cs">
       <Link>Common\System\Security\Cryptography\RsaPaddingProcessor.cs</Link>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.cs">
-      <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.cs</Link>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml</DependentUpon>
+    </Compile>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.manual.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.manual.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml</DependentUpon>
+    </Compile>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\AttributeAsn.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\AttributeAsn.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AttributeAsn.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\AttributeAsn.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\AttributeAsn.xml</DependentUpon>
+    </Compile>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\CurveAsn.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\CurveAsn.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\CurveAsn.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\CurveAsn.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\CurveAsn.xml</DependentUpon>
+    </Compile>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\DssParms.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\DssParms.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\DssParms.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\DssParms.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\DssParms.xml</DependentUpon>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AttributeAsn.cs">
-      <Link>Common\System\Security\Cryptography\Asn1\AttributeAsn.cs</Link>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\ECDomainParameters.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\ECDomainParameters.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\ECDomainParameters.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\ECDomainParameters.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\ECDomainParameters.xml</DependentUpon>
+    </Compile>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\ECPrivateKey.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\ECPrivateKey.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\ECPrivateKey.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\ECPrivateKey.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\ECPrivateKey.xml</DependentUpon>
+    </Compile>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml</DependentUpon>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.cs">
-      <Link>Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.cs</Link>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\FieldID.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\FieldID.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\FieldID.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\FieldID.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\FieldID.xml</DependentUpon>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBEParameter.cs">
-      <Link>Common\System\Security\Cryptography\Asn1\PBEParameter.cs</Link>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBEParameter.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\PBEParameter.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBEParameter.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\PBEParameter.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\PBEParameter.xml</DependentUpon>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBES2Params.cs">
-      <Link>Common\System\Security\Cryptography\Asn1\PBES2Params.cs</Link>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBES2Params.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\PBES2Params.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBES2Params.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\PBES2Params.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\PBES2Params.xml</DependentUpon>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2Params.cs">
-      <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2Params.cs</Link>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2Params.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2Params.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2Params.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2Params.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\Pbkdf2Params.xml</DependentUpon>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.cs">
-      <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.cs</Link>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml</DependentUpon>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.cs">
-      <Link>Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.cs</Link>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml</DependentUpon>
     </Compile>
     <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml">
       <Link>Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml</Link>
       <Link>Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.manual.cs</Link>
       <DependentUpon>Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml</DependentUpon>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.cs">
-      <Link>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.cs</Link>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\RSAPrivateKeyAsn.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\RSAPrivateKeyAsn.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\RSAPrivateKeyAsn.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\RSAPrivateKeyAsn.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\RSAPrivateKeyAsn.xml</DependentUpon>
+    </Compile>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\RSAPublicKeyAsn.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\RSAPublicKeyAsn.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\RSAPublicKeyAsn.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\RSAPublicKeyAsn.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\RSAPublicKeyAsn.xml</DependentUpon>
+    </Compile>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\SpecifiedECDomain.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\SpecifiedECDomain.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\SpecifiedECDomain.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\SpecifiedECDomain.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\SpecifiedECDomain.xml</DependentUpon>
+    </Compile>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml</DependentUpon>
     </Compile>
   </ItemGroup>
   <ItemGroup Condition="'$(TargetsWindows)' == 'true'">
     <Compile Include="$(CommonPath)\System\Security\Cryptography\ECDsaSecurityTransforms.cs">
       <Link>Common\System\Security\Cryptography\ECDsaSecurityTransforms.cs</Link>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\KeyBlobHelpers.cs">
-      <Link>Common\System\Security\Cryptography\KeyBlobHelpers.cs</Link>
-    </Compile>
     <Compile Include="$(CommonPath)\System\Security\Cryptography\RSASecurityTransforms.cs">
       <Link>Common\System\Security\Cryptography\RSASecurityTransforms.cs</Link>
     </Compile>
     <Compile Include="$(CommonPath)\Microsoft\Win32\SafeHandles\SafeEvpCipherCtxHandle.Unix.cs">
       <Link>Common\Microsoft\Win32\SafeHandles\SafeEvpCipherCtxHandle.Unix.cs</Link>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\DerEncoder.cs">
-      <Link>Common\System\Security\Cryptography\DerEncoder.cs</Link>
-    </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\DerSequenceReader.cs">
-      <Link>Common\System\Security\Cryptography\DerSequenceReader.cs</Link>
-    </Compile>
     <Compile Include="$(CommonPath)\System\Security\Cryptography\ECDiffieHellmanDerivation.cs">
       <Link>Common\System\Security\Cryptography\ECDiffieHellmanDerivation.cs</Link>
     </Compile>
   <ItemGroup Condition="'$(TargetsUnix)' == 'true'">
     <Reference Include="System.Runtime.Numerics" />
   </ItemGroup>
+  <ItemGroup>
+    <None Include="@(AsnXml)" /> 
+  </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Asn1/CurveAsn.cs b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Asn1/CurveAsn.cs
deleted file mode 100644 (file)
index 91d0186..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-// 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.Runtime.InteropServices;
-
-namespace System.Security.Cryptography.Asn1
-{
-    // https://www.secg.org/sec1-v2.pdf, C.2
-    //
-    // Curve ::= SEQUENCE {
-    //   a FieldElement,
-    //   b FieldElement,
-    //   seed BIT STRING OPTIONAL
-    //   -- Shall be present if used in SpecifiedECDomain
-    //   -- with version equal to ecdpVer2 or ecdpVer3
-    // }
-    //
-    // FieldElement ::= OCTET STRING
-    [StructLayout(LayoutKind.Sequential)]
-    internal struct CurveAsn
-    {
-        [OctetString]
-        public ReadOnlyMemory<byte> A;
-
-        [OctetString]
-        public ReadOnlyMemory<byte> B;
-
-        [BitString, OptionalValue]
-        public ReadOnlyMemory<byte>? Seed;
-    }
-}
diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Asn1/DSSParms.cs b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Asn1/DSSParms.cs
deleted file mode 100644 (file)
index 5284127..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-// 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.Numerics;
-using System.Runtime.InteropServices;
-
-namespace System.Security.Cryptography.Asn1
-{
-    // https://tools.ietf.org/html/rfc3279#section-2.3.2
-    //
-    // Dss-Parms  ::=  SEQUENCE  {
-    //   p             INTEGER,
-    //   q             INTEGER,
-    //   g             INTEGER  }
-    [StructLayout(LayoutKind.Sequential)]
-    internal struct DssParms
-    {
-        public BigInteger P;
-        public BigInteger Q;
-        public BigInteger G;
-    }
-}
diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Asn1/DsaPrivateKeyAsn.cs b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Asn1/DsaPrivateKeyAsn.cs
deleted file mode 100644 (file)
index 41a2a2a..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// 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.Runtime.InteropServices;
-
-namespace System.Security.Cryptography.Asn1
-{
-    // The private key field is just an integer, but we need the raw bytes.
-    [Choice]
-    [StructLayout(LayoutKind.Sequential)]
-    internal struct DsaPrivateKeyAsn
-    {
-        [Integer]
-        public ReadOnlyMemory<byte>? X;
-    }
-}
diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Asn1/ECDomainParameters.cs b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Asn1/ECDomainParameters.cs
deleted file mode 100644 (file)
index c409a21..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-// 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.Runtime.InteropServices;
-
-namespace System.Security.Cryptography.Asn1
-{
-    // https://www.secg.org/sec1-v2.pdf, C.2
-    //
-    // ECDomainParameters{ECDOMAIN:IOSet} ::= CHOICE {
-    //   specified SpecifiedECDomain,
-    //   named ECDOMAIN.&id({IOSet}),
-    //   implicitCA NULL
-    // }
-    [Choice]
-    [StructLayout(LayoutKind.Sequential)]
-    internal struct ECDomainParameters
-    {
-        public SpecifiedECDomain? Specified;
-
-        [ObjectIdentifier(PopulateFriendlyName = true)]
-        public Oid Named;
-    }
-}
diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Asn1/ECPrivateKey.cs b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Asn1/ECPrivateKey.cs
deleted file mode 100644 (file)
index 6fda3cb..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-// 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.Runtime.InteropServices;
-
-namespace System.Security.Cryptography.Asn1
-{
-    // https://www.secg.org/sec1-v2.pdf, C.4
-    //
-    // ECPrivateKey ::= SEQUENCE {
-    //   version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
-    //   privateKey OCTET STRING,
-    //   parameters [0] ECDomainParameters {{ SECGCurveNames }} OPTIONAL,
-    //   publicKey [1] BIT STRING OPTIONAL
-    // }
-    [StructLayout(LayoutKind.Sequential)]
-    internal struct ECPrivateKey
-    {
-        public byte Version;
-
-        [OctetString]
-        public ReadOnlyMemory<byte> PrivateKey;
-
-        [OptionalValue]
-        [ExpectedTag(0, ExplicitTag = true)]
-        public ECDomainParameters? Parameters;
-
-        [BitString, OptionalValue]
-        [ExpectedTag(1, ExplicitTag = true)]
-        public ReadOnlyMemory<byte>? PublicKey;
-    }
-}
diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Asn1/FieldID.cs b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Asn1/FieldID.cs
deleted file mode 100644 (file)
index 28a5285..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-// 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.Runtime.InteropServices;
-
-namespace System.Security.Cryptography.Asn1
-{
-    // https://www.secg.org/sec1-v2.pdf, C.1
-    //
-    // FieldID { FIELD-ID:IOSet } ::= SEQUENCE { -- Finite field
-    //   fieldType FIELD-ID.&id({IOSet}),
-    //   parameters FIELD-ID.&Type({IOSet}{@fieldType})
-    // }
-    [StructLayout(LayoutKind.Sequential)]
-    internal struct FieldID
-    {
-        [ObjectIdentifier]
-        public string FieldType;
-
-        [AnyValue]
-        public ReadOnlyMemory<byte> Parameters;
-    }
-}
diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Asn1/RSAPrivateKeyAsn.cs b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Asn1/RSAPrivateKeyAsn.cs
deleted file mode 100644 (file)
index 9652e96..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-// 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.Numerics;
-using System.Runtime.InteropServices;
-
-namespace System.Security.Cryptography.Asn1
-{
-    // https://tools.ietf.org/html/rfc3447#appendix-C
-    //
-    // RSAPrivateKey ::= SEQUENCE {
-    //   version           Version,
-    //   modulus           INTEGER,  -- n
-    //   publicExponent    INTEGER,  -- e
-    //   privateExponent   INTEGER,  -- d
-    //   prime1            INTEGER,  -- p
-    //   prime2            INTEGER,  -- q
-    //   exponent1         INTEGER,  -- d mod (p-1)
-    //   exponent2         INTEGER,  -- d mod (q-1)
-    //   coefficient       INTEGER,  -- (inverse of q) mod p
-    //   otherPrimeInfos   OtherPrimeInfos OPTIONAL
-    // }
-    //
-    // Version ::= INTEGER { two-prime(0), multi(1) }
-    //   (CONSTRAINED BY {
-    //     -- version must be multi if otherPrimeInfos present --
-    //   })
-    //
-    // Since we don't support otherPrimeInfos (Version=1) just don't map it in.
-    [StructLayout(LayoutKind.Sequential)]
-    internal struct RSAPrivateKeyAsn
-    {
-        internal byte Version;
-        internal BigInteger Modulus;
-        internal BigInteger PublicExponent;
-        internal BigInteger PrivateExponent;
-        internal BigInteger Prime1;
-        internal BigInteger Prime2;
-        internal BigInteger Exponent1;
-        internal BigInteger Exponent2;
-        internal BigInteger Coefficient;
-    }
-}
diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Asn1/RSAPublicKeyAsn.cs b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Asn1/RSAPublicKeyAsn.cs
deleted file mode 100644 (file)
index ff6038b..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-// 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.Numerics;
-using System.Runtime.InteropServices;
-
-namespace System.Security.Cryptography.Asn1
-{
-    // https://tools.ietf.org/html/rfc3447#appendix-C
-    //
-    // RSAPublicKey ::= SEQUENCE {
-    //   modulus           INTEGER,  -- n
-    //   publicExponent    INTEGER   -- e
-    // }
-    [StructLayout(LayoutKind.Sequential)]
-    internal struct RSAPublicKey
-    {
-        internal BigInteger Modulus;
-        internal BigInteger PublicExponent;
-    }
-}
diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Asn1/SpecifiedECDomain.cs b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Asn1/SpecifiedECDomain.cs
deleted file mode 100644 (file)
index 66104f8..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-// 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.Runtime.InteropServices;
-
-namespace System.Security.Cryptography.Asn1
-{
-    // https://www.secg.org/sec1-v2.pdf, C.2
-    //
-    // SpecifiedECDomain ::= SEQUENCE {
-    //   version SpecifiedECDomainVersion(ecdpVer1 | ecdpVer2 | ecdpVer3, ...),
-    //   fieldID FieldID {{FieldTypes}},
-    //   curve Curve,
-    //   base ECPoint,
-    //   order INTEGER,
-    //   cofactor INTEGER OPTIONAL,
-    //   hash HashAlgorithm OPTIONAL,
-    //   ...
-    // }
-    //
-    // HashAlgorithm ::= AlgorithmIdentifier {{ HashFunctions }}
-    // ECPoint ::= OCTET STRING
-    [StructLayout(LayoutKind.Sequential)]
-    internal struct SpecifiedECDomain
-    {
-        public byte Version;
-
-        public FieldID FieldID;
-
-        public CurveAsn Curve;
-
-        [OctetString]
-        public ReadOnlyMemory<byte> Base;
-
-        [Integer]
-        public ReadOnlyMemory<byte> Order;
-
-        [Integer, OptionalValue]
-        public ReadOnlyMemory<byte>? Cofactor;
-
-        [OptionalValue]
-        [ObjectIdentifier(PopulateFriendlyName = true)]
-        public Oid Hash;
-    }
-}
index 731be04..b620c8a 100644 (file)
@@ -13,11 +13,6 @@ namespace System.Security.Cryptography
 {
     public abstract partial class DSA : AsymmetricAlgorithm
     {
-        private static readonly string[] s_validOids =
-        {
-            Oids.Dsa,
-        };
-
         public abstract DSAParameters ExportParameters(bool includePrivateParameters);
 
         public abstract void ImportParameters(DSAParameters parameters);
@@ -308,15 +303,7 @@ namespace System.Security.Cryptography
             {
                 try
                 {
-                    AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
-
-                    writer.PushSequence();
-                    writer.WriteInteger(0);
-                    WriteAlgorithmId(writer, dsaParameters);
-                    WriteKeyComponent(writer, dsaParameters.X, bitString: false);
-                    writer.PopSequence();
-
-                    return writer;
+                    return DSAKeyFormatHelper.WritePkcs8(dsaParameters);
                 }
                 finally
                 {
@@ -328,49 +315,7 @@ namespace System.Security.Cryptography
         private AsnWriter WriteSubjectPublicKeyInfo()
         {
             DSAParameters dsaParameters = ExportParameters(false);
-
-            AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
-
-            writer.PushSequence();
-            WriteAlgorithmId(writer, dsaParameters);
-            WriteKeyComponent(writer, dsaParameters.Y, bitString: true);
-            writer.PopSequence();
-
-            return writer;
-        }
-
-        private void WriteAlgorithmId(AsnWriter writer, in DSAParameters dsaParameters)
-        {
-            writer.PushSequence();
-            writer.WriteObjectIdentifier(Oids.Dsa);
-
-            // Dss-Parms ::= SEQUENCE {
-            //   p INTEGER,
-            //   q INTEGER,
-            //   g INTEGER  }
-            writer.PushSequence();
-            writer.WriteKeyParameterInteger(dsaParameters.P);
-            writer.WriteKeyParameterInteger(dsaParameters.Q);
-            writer.WriteKeyParameterInteger(dsaParameters.G);
-            writer.PopSequence();
-            writer.PopSequence();
-        }
-
-        private void WriteKeyComponent(AsnWriter writer, byte[] component, bool bitString)
-        {
-            using (AsnWriter inner = new AsnWriter(AsnEncodingRules.DER))
-            {
-                inner.WriteKeyParameterInteger(component);
-
-                if (bitString)
-                {
-                    writer.WriteBitString(inner.EncodeAsSpan());
-                }
-                else
-                {
-                    writer.WriteOctetString(inner.EncodeAsSpan());
-                }
-            }
+            return DSAKeyFormatHelper.WriteSubjectPublicKeyInfo(dsaParameters);
         }
 
         public override unsafe void ImportEncryptedPkcs8PrivateKey(
@@ -378,11 +323,9 @@ namespace System.Security.Cryptography
             ReadOnlySpan<byte> source,
             out int bytesRead)
         {
-            KeyFormatHelper.ReadEncryptedPkcs8<DSAParameters, DsaPrivateKeyAsn>(
-                s_validOids,
+            DSAKeyFormatHelper.ReadEncryptedPkcs8(
                 source,
                 passwordBytes,
-                ReadDsaPrivateKey,
                 out int localRead,
                 out DSAParameters ret);
 
@@ -406,11 +349,9 @@ namespace System.Security.Cryptography
             ReadOnlySpan<byte> source,
             out int bytesRead)
         {
-            KeyFormatHelper.ReadEncryptedPkcs8<DSAParameters, DsaPrivateKeyAsn>(
-                s_validOids,
+            DSAKeyFormatHelper.ReadEncryptedPkcs8(
                 source,
                 password,
-                ReadDsaPrivateKey, 
                 out int localRead,
                 out DSAParameters ret);
 
@@ -433,10 +374,8 @@ namespace System.Security.Cryptography
             ReadOnlySpan<byte> source,
             out int bytesRead)
         {
-            KeyFormatHelper.ReadPkcs8<DSAParameters, DsaPrivateKeyAsn>(
-                s_validOids,
+            DSAKeyFormatHelper.ReadPkcs8(
                 source,
-                ReadDsaPrivateKey, 
                 out int localRead,
                 out DSAParameters key);
 
@@ -455,67 +394,12 @@ namespace System.Security.Cryptography
             bytesRead = localRead;
         }
 
-        private void ReadDsaPrivateKey(
-            in DsaPrivateKeyAsn key,
-            in AlgorithmIdentifierAsn algId,
-            out DSAParameters ret)
-        {
-            if (!algId.Parameters.HasValue)
-            {
-                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
-            }
-
-            DssParms parms =
-                AsnSerializer.Deserialize<DssParms>(algId.Parameters.Value, AsnEncodingRules.BER);
-
-            ret = new DSAParameters
-            {
-                P = parms.P.ToByteArray(isUnsigned: true, isBigEndian: true),
-                Q = parms.Q.ToByteArray(isUnsigned: true, isBigEndian: true),
-            };
-
-            ret.G = parms.G.ExportKeyParameter(ret.P.Length);
-
-            // Force a positive interpretation because Windows sometimes writes negative numbers.
-            BigInteger x = new BigInteger(key.X.Value.Span, isUnsigned: true, isBigEndian: true);
-            ret.X = x.ExportKeyParameter(ret.Q.Length);
-
-            // The public key is not contained within the format, calculate it.
-            BigInteger y = BigInteger.ModPow(parms.G, x, parms.P);
-            ret.Y = y.ExportKeyParameter(ret.P.Length);
-        }
-
-        private void ReadDsaPublicKey(
-            in BigInteger y,
-            in AlgorithmIdentifierAsn algId,
-            out DSAParameters ret)
-        {
-            if (!algId.Parameters.HasValue)
-            {
-                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
-            }
-
-            DssParms parms =
-                AsnSerializer.Deserialize<DssParms>(algId.Parameters.Value, AsnEncodingRules.BER);
-
-            ret = new DSAParameters
-            {
-                P = parms.P.ToByteArray(isUnsigned: true, isBigEndian: true),
-                Q = parms.Q.ToByteArray(isUnsigned: true, isBigEndian: true),
-            };
-
-            ret.G = parms.G.ExportKeyParameter(ret.P.Length);
-            ret.Y = y.ExportKeyParameter(ret.P.Length);
-        }
-
         public override void ImportSubjectPublicKeyInfo(
             ReadOnlySpan<byte> source,
             out int bytesRead)
         {
-            KeyFormatHelper.ReadSubjectPublicKeyInfo<DSAParameters, BigInteger>(
-                s_validOids,
+            DSAKeyFormatHelper.ReadSubjectPublicKeyInfo(
                 source,
-                ReadDsaPublicKey,
                 out int localRead,
                 out DSAParameters key);
 
index a869b58..7804055 100644 (file)
@@ -196,7 +196,7 @@ namespace System.Security.Cryptography
             {
                 try
                 {
-                    using (AsnWriter pkcs8PrivateKey = ecParameters.WritePkcs8PrivateKey())
+                    using (AsnWriter pkcs8PrivateKey = EccKeyFormatHelper.WritePkcs8PrivateKey(ecParameters))
                     using (AsnWriter writer = KeyFormatHelper.WriteEncryptedPkcs8(
                         passwordBytes,
                         pkcs8PrivateKey,
@@ -232,7 +232,7 @@ namespace System.Security.Cryptography
             {
                 try
                 {
-                    using (AsnWriter pkcs8PrivateKey = ecParameters.WritePkcs8PrivateKey())
+                    using (AsnWriter pkcs8PrivateKey = EccKeyFormatHelper.WritePkcs8PrivateKey(ecParameters))
                     using (AsnWriter writer = KeyFormatHelper.WriteEncryptedPkcs8(
                         password,
                         pkcs8PrivateKey,
@@ -258,7 +258,7 @@ namespace System.Security.Cryptography
             {
                 try
                 {
-                    using (AsnWriter writer = ecParameters.WritePkcs8PrivateKey())
+                    using (AsnWriter writer = EccKeyFormatHelper.WritePkcs8PrivateKey(ecParameters))
                     {
                         return writer.TryEncode(destination, out bytesWritten);
                     }
@@ -276,7 +276,7 @@ namespace System.Security.Cryptography
         {
             ECParameters ecParameters = ExportParameters(false);
 
-            using (AsnWriter writer = ecParameters.WriteSubjectPublicKeyInfo())
+            using (AsnWriter writer = EccKeyFormatHelper.WriteSubjectPublicKeyInfo(ecParameters))
             {
                 return writer.TryEncode(destination, out bytesWritten);
             }
@@ -287,11 +287,11 @@ namespace System.Security.Cryptography
             ReadOnlySpan<byte> source,
             out int bytesRead)
         {
-            KeyFormatHelper.ReadEncryptedPkcs8<ECParameters, ECPrivateKey>(
+            KeyFormatHelper.ReadEncryptedPkcs8<ECParameters>(
                 s_validOids,
                 source,
                 passwordBytes,
-                ECParameters.FromECPrivateKey,
+                EccKeyFormatHelper.FromECPrivateKey,
                 out int localRead,
                 out ECParameters ret);
 
@@ -314,11 +314,11 @@ namespace System.Security.Cryptography
             ReadOnlySpan<byte> source,
             out int bytesRead)
         {
-            KeyFormatHelper.ReadEncryptedPkcs8<ECParameters, ECPrivateKey>(
+            KeyFormatHelper.ReadEncryptedPkcs8<ECParameters>(
                 s_validOids,
                 source,
                 password,
-                ECParameters.FromECPrivateKey,
+                EccKeyFormatHelper.FromECPrivateKey,
                 out int localRead,
                 out ECParameters ret);
 
@@ -340,10 +340,10 @@ namespace System.Security.Cryptography
             ReadOnlySpan<byte> source,
             out int bytesRead)
         {
-            KeyFormatHelper.ReadPkcs8<ECParameters, ECPrivateKey>(
+            KeyFormatHelper.ReadPkcs8<ECParameters>(
                 s_validOids,
                 source,
-                ECParameters.FromECPrivateKey,
+                EccKeyFormatHelper.FromECPrivateKey,
                 out int localRead,
                 out ECParameters key);
 
@@ -365,10 +365,10 @@ namespace System.Security.Cryptography
             ReadOnlySpan<byte> source,
             out int bytesRead)
         {
-            KeyFormatHelper.ReadSubjectPublicKeyInfo<ECParameters, ReadOnlyMemory<byte>>(
+            KeyFormatHelper.ReadSubjectPublicKeyInfo<ECParameters>(
                 s_validOids,
                 source,
-                ECParameters.FromECPublicKey,
+                EccKeyFormatHelper.FromECPublicKey,
                 out int localRead,
                 out ECParameters key);
 
@@ -378,7 +378,7 @@ namespace System.Security.Cryptography
 
         public virtual unsafe void ImportECPrivateKey(ReadOnlySpan<byte> source, out int bytesRead)
         {
-            ECParameters ecParameters = ECParameters.FromECPrivateKey(source, out int localRead);
+            ECParameters ecParameters = EccKeyFormatHelper.FromECPrivateKey(source, out int localRead);
 
             fixed (byte* privPin = ecParameters.D)
             {
@@ -402,7 +402,7 @@ namespace System.Security.Cryptography
             {
                 try
                 {
-                    using (AsnWriter writer = ecParameters.WriteECPrivateKey())
+                    using (AsnWriter writer = EccKeyFormatHelper.WriteECPrivateKey(ecParameters))
                     {
                         return writer.Encode();
                     }
@@ -422,7 +422,7 @@ namespace System.Security.Cryptography
             {
                 try
                 {
-                    using (AsnWriter writer = ecParameters.WriteECPrivateKey())
+                    using (AsnWriter writer = EccKeyFormatHelper.WriteECPrivateKey(ecParameters))
                     {
                         return writer.TryEncode(destination, out bytesWritten);
                     }
index e2c2d95..fa8e0e2 100644 (file)
@@ -263,7 +263,7 @@ namespace System.Security.Cryptography
             {
                 try
                 {
-                    using (AsnWriter pkcs8PrivateKey = ecParameters.WritePkcs8PrivateKey())
+                    using (AsnWriter pkcs8PrivateKey = EccKeyFormatHelper.WritePkcs8PrivateKey(ecParameters))
                     using (AsnWriter writer = KeyFormatHelper.WriteEncryptedPkcs8(
                         passwordBytes,
                         pkcs8PrivateKey,
@@ -299,7 +299,7 @@ namespace System.Security.Cryptography
             {
                 try
                 {
-                    using (AsnWriter pkcs8PrivateKey = ecParameters.WritePkcs8PrivateKey())
+                    using (AsnWriter pkcs8PrivateKey = EccKeyFormatHelper.WritePkcs8PrivateKey(ecParameters))
                     using (AsnWriter writer = KeyFormatHelper.WriteEncryptedPkcs8(
                         password,
                         pkcs8PrivateKey,
@@ -325,7 +325,7 @@ namespace System.Security.Cryptography
             {
                 try
                 {
-                    using (AsnWriter writer = ecParameters.WritePkcs8PrivateKey())
+                    using (AsnWriter writer = EccKeyFormatHelper.WritePkcs8PrivateKey(ecParameters))
                     {
                         return writer.TryEncode(destination, out bytesWritten);
                     }
@@ -343,7 +343,7 @@ namespace System.Security.Cryptography
         {
             ECParameters ecParameters = ExportParameters(false);
 
-            using (AsnWriter writer = ecParameters.WriteSubjectPublicKeyInfo())
+            using (AsnWriter writer = EccKeyFormatHelper.WriteSubjectPublicKeyInfo(ecParameters))
             {
                 return writer.TryEncode(destination, out bytesWritten);
             }
@@ -354,11 +354,11 @@ namespace System.Security.Cryptography
             ReadOnlySpan<byte> source,
             out int bytesRead)
         {
-            KeyFormatHelper.ReadEncryptedPkcs8<ECParameters, ECPrivateKey>(
+            KeyFormatHelper.ReadEncryptedPkcs8<ECParameters>(
                 s_validOids,
                 source,
                 passwordBytes,
-                ECParameters.FromECPrivateKey,
+                EccKeyFormatHelper.FromECPrivateKey,
                 out int localRead,
                 out ECParameters ret);
 
@@ -381,11 +381,11 @@ namespace System.Security.Cryptography
             ReadOnlySpan<byte> source,
             out int bytesRead)
         {
-            KeyFormatHelper.ReadEncryptedPkcs8<ECParameters, ECPrivateKey>(
+            KeyFormatHelper.ReadEncryptedPkcs8<ECParameters>(
                 s_validOids,
                 source,
                 password,
-                ECParameters.FromECPrivateKey,
+                EccKeyFormatHelper.FromECPrivateKey,
                 out int localRead,
                 out ECParameters ret);
 
@@ -407,10 +407,10 @@ namespace System.Security.Cryptography
             ReadOnlySpan<byte> source,
             out int bytesRead)
         {
-            KeyFormatHelper.ReadPkcs8<ECParameters, ECPrivateKey>(
+            KeyFormatHelper.ReadPkcs8<ECParameters>(
                 s_validOids,
                 source,
-                ECParameters.FromECPrivateKey,
+                EccKeyFormatHelper.FromECPrivateKey,
                 out int localRead,
                 out ECParameters key);
 
@@ -432,10 +432,10 @@ namespace System.Security.Cryptography
             ReadOnlySpan<byte> source,
             out int bytesRead)
         {
-            KeyFormatHelper.ReadSubjectPublicKeyInfo<ECParameters, ReadOnlyMemory<byte>>(
+            KeyFormatHelper.ReadSubjectPublicKeyInfo<ECParameters>(
                 s_validOids,
                 source,
-                ECParameters.FromECPublicKey,
+                EccKeyFormatHelper.FromECPublicKey,
                 out int localRead,
                 out ECParameters key);
 
@@ -445,7 +445,7 @@ namespace System.Security.Cryptography
 
         public virtual unsafe void ImportECPrivateKey(ReadOnlySpan<byte> source, out int bytesRead)
         {
-            ECParameters ecParameters = ECParameters.FromECPrivateKey(source, out int localRead);
+            ECParameters ecParameters = EccKeyFormatHelper.FromECPrivateKey(source, out int localRead);
 
             fixed (byte* privPin = ecParameters.D)
             {
@@ -469,7 +469,7 @@ namespace System.Security.Cryptography
             {
                 try
                 {
-                    using (AsnWriter writer = ecParameters.WriteECPrivateKey())
+                    using (AsnWriter writer = EccKeyFormatHelper.WriteECPrivateKey(ecParameters))
                     {
                         return writer.Encode();
                     }
@@ -489,7 +489,7 @@ namespace System.Security.Cryptography
             {
                 try
                 {
-                    using (AsnWriter writer = ecParameters.WriteECPrivateKey())
+                    using (AsnWriter writer = EccKeyFormatHelper.WriteECPrivateKey(ecParameters))
                     {
                         return writer.TryEncode(destination, out bytesWritten);
                     }
index e42b51e..ee305ce 100644 (file)
@@ -66,374 +66,5 @@ namespace System.Security.Cryptography
 
             Curve.Validate();
         }
-
-        internal static unsafe ECParameters FromECPrivateKey(ReadOnlySpan<byte> key, out int bytesRead)
-        {
-            fixed (byte* ptr = &MemoryMarshal.GetReference(key))
-            {
-                using (MemoryManager<byte> manager = new PointerMemoryManager<byte>(ptr, key.Length))
-                {
-                    ECPrivateKey parsedKey =
-                        AsnSerializer.Deserialize<ECPrivateKey>(manager.Memory, AsnEncodingRules.BER, out bytesRead);
-
-                    ECParameters ret;
-                    AlgorithmIdentifierAsn algId = default;
-                    FromECPrivateKey(parsedKey, algId, out ret);
-                    return ret;
-                }
-            }
-        }
-
-        internal static void FromECPrivateKey(
-            in ECPrivateKey key,
-            in AlgorithmIdentifierAsn algId,
-            out ECParameters ret)
-        {
-            ValidateParameters(key.Parameters, algId);
-
-            if (key.Version != 1)
-            {
-                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
-            }
-
-            // Implementation limitation
-            if (key.PublicKey == null)
-            {
-                throw new CryptographicException(SR.Cryptography_NotValidPublicOrPrivateKey);
-            }
-
-            ReadOnlySpan<byte> publicKeyBytes = key.PublicKey.Value.Span;
-
-            if (publicKeyBytes.Length == 0)
-            {
-                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
-            }
-
-            // Implementation limitation
-            // 04 (Uncompressed ECPoint) is almost always used.
-            if (publicKeyBytes[0] != 0x04)
-            {
-                throw new CryptographicException(SR.Cryptography_NotValidPublicOrPrivateKey);
-            }
-
-            // https://www.secg.org/sec1-v2.pdf, 2.3.4, #3 (M has length 2 * CEIL(log2(q)/8) + 1)
-            if (publicKeyBytes.Length != 2 * key.PrivateKey.Length + 1)
-            {
-                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
-            }
-
-            ECDomainParameters domainParameters;
-
-            if (key.Parameters != null)
-            {
-                domainParameters = key.Parameters.Value;
-            }
-            else
-            {
-                domainParameters = AsnSerializer.Deserialize<ECDomainParameters>(
-                    algId.Parameters.Value,
-                    AsnEncodingRules.DER);
-            }
-
-            ret = new ECParameters
-            {
-                Curve = GetCurve(domainParameters),
-                Q =
-                {
-                    X = publicKeyBytes.Slice(1, key.PrivateKey.Length).ToArray(),
-                    Y = publicKeyBytes.Slice(1 + key.PrivateKey.Length).ToArray(),
-                },
-                D = key.PrivateKey.ToArray(),
-            };
-
-            ret.Validate();
-        }
-
-        internal static void FromECPublicKey(
-            in ReadOnlyMemory<byte> key,
-            in AlgorithmIdentifierAsn algId,
-            out ECParameters ret)
-        {
-            if (algId.Parameters == null)
-            {
-                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
-            }
-
-            ReadOnlySpan<byte> publicKeyBytes = key.Span;
-
-            if (publicKeyBytes.Length == 0)
-            {
-                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
-            }
-
-            // Implementation limitation.
-            // 04 (Uncompressed ECPoint) is almost always used.
-            if (publicKeyBytes[0] != 0x04)
-            {
-                throw new CryptographicException(SR.Cryptography_NotValidPublicOrPrivateKey);
-            }
-
-            // https://www.secg.org/sec1-v2.pdf, 2.3.4, #3 (M has length 2 * CEIL(log2(q)/8) + 1)
-            if ((publicKeyBytes.Length & 0x01) != 1)
-            {
-                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
-            }
-
-            int fieldWidth = publicKeyBytes.Length / 2;
-
-            ECDomainParameters domainParameters = AsnSerializer.Deserialize<ECDomainParameters>(
-                algId.Parameters.Value,
-                AsnEncodingRules.DER);
-
-            ret = new ECParameters
-            {
-                Curve = GetCurve(domainParameters),
-                Q =
-                {
-                    X = publicKeyBytes.Slice(1, fieldWidth).ToArray(),
-                    Y = publicKeyBytes.Slice(1 + fieldWidth).ToArray(),
-                },
-            };
-
-            ret.Validate();
-        }
-
-        private static void ValidateParameters(ECDomainParameters? keyParameters, in AlgorithmIdentifierAsn algId)
-        {
-            // At least one is required
-            if (keyParameters == null && algId.Parameters == null)
-            {
-                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
-            }
-
-            // If they are both specified they must match.
-            if (keyParameters != null && algId.Parameters != null)
-            {
-                ReadOnlySpan<byte> algIdParameters = algId.Parameters.Value.Span;
-                byte[] verify = ArrayPool<byte>.Shared.Rent(algIdParameters.Length);
-
-                try
-                {
-                    // X.509 SubjectPublicKeyInfo specifies DER encoding.
-                    // RFC 5915 specifies DER encoding for EC Private Keys.
-                    // So we can compare as DER.
-                    using (AsnWriter writer = AsnSerializer.Serialize(keyParameters.Value, AsnEncodingRules.DER))
-                    {
-                        if (!writer.TryEncode(verify, out int written) ||
-                            written != algIdParameters.Length ||
-                            !algIdParameters.SequenceEqual(verify.AsSpan(0, written)))
-                        {
-                            throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
-                        }
-                    }
-                }
-                finally
-                {
-                    // verify contains public information and does not need to be cleared.
-                    ArrayPool<byte>.Shared.Return(verify);
-                }
-            }
-        }
-
-        private static ECCurve GetCurve(in ECDomainParameters domainParameters)
-        {
-            if (domainParameters.Named == null)
-            {
-                throw new CryptographicException(SR.Cryptography_ECC_NamedCurvesOnly);
-            }
-
-            Oid curveOid = domainParameters.Named;
-
-            switch (curveOid.Value)
-            {
-                case Oids.secp256r1:
-                    curveOid = new Oid(Oids.secp256r1, nameof(ECCurve.NamedCurves.nistP256));
-                    break;
-                case Oids.secp384r1:
-                    curveOid = new Oid(Oids.secp384r1, nameof(ECCurve.NamedCurves.nistP384));
-                    break;
-                case Oids.secp521r1:
-                    curveOid = new Oid(Oids.secp521r1, nameof(ECCurve.NamedCurves.nistP521));
-                    break;
-            }
-
-            return ECCurve.CreateFromOid(curveOid);
-        }
-
-        internal AsnWriter WriteSubjectPublicKeyInfo()
-        {
-            Validate();
-
-            if (!Curve.IsNamed)
-            {
-                throw new CryptographicException(SR.Cryptography_ECC_NamedCurvesOnly);
-            }
-
-            // Since the public key format for EC keys is not ASN.1,
-            // write the SPKI structure manually.
-
-            AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
-
-            // SubjectPublicKeyInfo
-            writer.PushSequence();
-
-            // algorithm
-            WriteAlgorithmIdentifier(writer);
-
-            // subjectPublicKey
-            WriteUncompressedPublicKey(writer);
-
-            writer.PopSequence();
-            return writer;
-        }
-
-        private AsnWriter WriteAlgorithmIdentifier()
-        {
-            AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
-            WriteAlgorithmIdentifier(writer);
-            return writer;
-        }
-
-        private void WriteAlgorithmIdentifier(AsnWriter writer)
-        {
-            writer.PushSequence();
-
-            writer.WriteObjectIdentifier(Oids.EcPublicKey);
-            WriteEcParameters(writer);
-
-            writer.PopSequence();
-        }
-
-        internal AsnWriter WritePkcs8PrivateKey()
-        {
-            Validate();
-
-            if (D == null)
-            {
-                throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey);
-            }
-
-            if (!Curve.IsNamed)
-            {
-                throw new CryptographicException(SR.Cryptography_ECC_NamedCurvesOnly);
-            }
-
-            // Don't need the domain parameters because they're contained in the algId.
-            using (AsnWriter ecPrivateKey = WriteEcPrivateKey(includeDomainParameters: false))
-            using (AsnWriter algorithmIdentifier = WriteAlgorithmIdentifier())
-            {
-                return KeyFormatHelper.WritePkcs8(algorithmIdentifier, ecPrivateKey);
-            }
-        }
-
-        private void WriteEcParameters(AsnWriter writer)
-        {
-            if (Curve.IsNamed)
-            {
-                Oid oid = Curve.Oid;
-
-                // On Windows the FriendlyName is populated in places where the Value mightn't be.
-                if (string.IsNullOrEmpty(oid.Value))
-                {
-                    oid = Oid.FromFriendlyName(oid.FriendlyName, OidGroup.All);
-                }
-
-                writer.WriteObjectIdentifier(oid.Value);
-            }
-            else
-            {
-                throw new CryptographicException(SR.Cryptography_ECC_NamedCurvesOnly);
-            }
-        }
-
-        private void WriteUncompressedPublicKey(AsnWriter writer)
-        {
-            int publicKeyLength = Q.X.Length * 2 + 1;
-            Span<byte> publicKeyBytes = stackalloc byte[0];
-            byte[] publicKeyRented = null;
-
-            if (publicKeyLength < 256)
-            {
-                publicKeyBytes = stackalloc byte[publicKeyLength];
-            }
-            else
-            {
-                publicKeyRented = ArrayPool<byte>.Shared.Rent(publicKeyLength);
-                publicKeyBytes = publicKeyRented.AsSpan(0, publicKeyLength);
-            }
-
-            try
-            {
-                publicKeyBytes[0] = 0x04;
-                Q.X.AsSpan().CopyTo(publicKeyBytes.Slice(1));
-                Q.Y.AsSpan().CopyTo(publicKeyBytes.Slice(1 + Q.X.Length));
-
-                writer.WriteBitString(publicKeyBytes);
-            }
-            finally
-            {
-                CryptographicOperations.ZeroMemory(publicKeyBytes);
-
-                if (publicKeyRented != null)
-                {
-                    ArrayPool<byte>.Shared.Return(publicKeyRented);
-                }
-            }
-        }
-
-        internal AsnWriter WriteECPrivateKey()
-        {
-            return WriteEcPrivateKey(includeDomainParameters: true);
-        }
-
-        private AsnWriter WriteEcPrivateKey(bool includeDomainParameters)
-        {
-            bool returning = false;
-            AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
-
-            try
-            {
-                // ECPrivateKey
-                writer.PushSequence();
-
-                // version 1
-                writer.WriteInteger(1);
-
-                // privateKey
-                writer.WriteOctetString(D);
-
-                // domainParameters
-                if (includeDomainParameters)
-                {
-                    Asn1Tag explicit0 = new Asn1Tag(TagClass.ContextSpecific, 0, isConstructed: true);
-                    writer.PushSequence(explicit0);
-
-                    WriteEcParameters(writer);
-
-                    writer.PopSequence(explicit0);
-                }
-
-                // publicKey
-                {
-                    Asn1Tag explicit1 = new Asn1Tag(TagClass.ContextSpecific, 1, isConstructed: true);
-                    writer.PushSequence(explicit1);
-
-                    WriteUncompressedPublicKey(writer);
-
-                    writer.PopSequence(explicit1);
-                }
-
-                writer.PopSequence();
-                returning = true;
-                return writer;
-            }
-            finally
-            {
-                if (!returning)
-                {
-                    writer.Dispose();
-                }
-            }
-        }
     }
 }
index 57c2e8d..1904eb7 100644 (file)
@@ -12,11 +12,6 @@ namespace System.Security.Cryptography
 {
     public abstract partial class RSA : AsymmetricAlgorithm
     {
-        private static readonly string[] s_validOids =
-        {
-            Oids.Rsa,
-        };
-
         public static new RSA Create(string algName)
         {
             return (RSA)CryptoConfig.CreateFromName(algName);
@@ -348,13 +343,8 @@ namespace System.Security.Cryptography
                             continue;
                         }
 
-                        using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER))
+                        using (AsnWriter writer = RSAKeyFormatHelper.WriteSubjectPublicKeyInfo(rented.AsSpan(0, pkcs1Size)))
                         {
-                            writer.PushSequence();
-                            WriteAlgorithmIdentifier(writer);
-                            writer.WriteBitString(rented.AsSpan(0, pkcs1Size));
-                            writer.PopSequence();
-
                             return writer.TryEncode(destination, out bytesWritten);
                         }
                     }
@@ -401,24 +391,7 @@ namespace System.Security.Cryptography
                             continue;
                         }
 
-                        AsnWriter writer = new AsnWriter(AsnEncodingRules.BER);
-
-                        try
-                        {
-                            writer.PushSequence();
-                            // Version 0 format (no attributes)
-                            writer.WriteInteger(0);
-                            WriteAlgorithmIdentifier(writer);
-                            writer.WriteOctetString(rented.AsSpan(0, pkcs1Size));
-                            writer.PopSequence();
-
-                            return writer;
-                        }
-                        catch
-                        {
-                            writer.Dispose();
-                            throw;
-                        }
+                        return RSAKeyFormatHelper.WritePkcs8PrivateKey(rented.AsSpan(0, pkcs1Size));
                     }
                     finally
                     {
@@ -476,39 +449,11 @@ namespace System.Security.Cryptography
                 return writer.TryEncode(destination, out bytesWritten);
             }
         }
-       
-        private static void WriteAlgorithmIdentifier(AsnWriter writer)
-        {
-            writer.PushSequence();
-
-            // https://tools.ietf.org/html/rfc3447#appendix-C
-            //
-            // --
-            // -- When rsaEncryption is used in an AlgorithmIdentifier the
-            // -- parameters MUST be present and MUST be NULL.
-            // --
-            writer.WriteObjectIdentifier(Oids.Rsa);
-            writer.WriteNull();
-
-            writer.PopSequence();
-        }
 
         private AsnWriter WritePkcs1PublicKey()
         {
             RSAParameters rsaParameters = ExportParameters(false);
-
-            if (rsaParameters.Modulus == null || rsaParameters.Exponent == null)
-            {
-                throw new InvalidOperationException(SR.Cryptography_InvalidRsaParameters);
-            }
-
-            AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
-            writer.PushSequence();
-            writer.WriteKeyParameterInteger(rsaParameters.Modulus);
-            writer.WriteKeyParameterInteger(rsaParameters.Exponent);
-            writer.PopSequence();
-
-            return writer;
+            return RSAKeyFormatHelper.WritePkcs1PublicKey(rsaParameters);
         }
 
         private unsafe AsnWriter WritePkcs1PrivateKey()
@@ -524,38 +469,7 @@ namespace System.Security.Cryptography
             {
                 try
                 {
-                    if (rsaParameters.Modulus == null || rsaParameters.Exponent == null)
-                    {
-                        throw new InvalidOperationException(SR.Cryptography_InvalidRsaParameters);
-                    }
-
-                    if (rsaParameters.D == null ||
-                        rsaParameters.P == null ||
-                        rsaParameters.Q == null ||
-                        rsaParameters.DP == null ||
-                        rsaParameters.DQ == null ||
-                        rsaParameters.InverseQ == null)
-                    {
-                        throw new InvalidOperationException(SR.Cryptography_NotValidPrivateKey);
-                    }
-
-                    AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
-
-                    writer.PushSequence();
-
-                    // Format version 0
-                    writer.WriteInteger(0);
-                    writer.WriteKeyParameterInteger(rsaParameters.Modulus);
-                    writer.WriteKeyParameterInteger(rsaParameters.Exponent);
-                    writer.WriteKeyParameterInteger(rsaParameters.D);
-                    writer.WriteKeyParameterInteger(rsaParameters.P);
-                    writer.WriteKeyParameterInteger(rsaParameters.Q);
-                    writer.WriteKeyParameterInteger(rsaParameters.DP);
-                    writer.WriteKeyParameterInteger(rsaParameters.DQ);
-                    writer.WriteKeyParameterInteger(rsaParameters.InverseQ);
-
-                    writer.PopSequence();
-                    return writer;
+                    return RSAKeyFormatHelper.WritePkcs1PrivateKey(rsaParameters);
                 }
                 finally
                 {
@@ -570,8 +484,7 @@ namespace System.Security.Cryptography
             {
                 using (MemoryManager<byte> manager = new PointerMemoryManager<byte>(ptr, source.Length))
                 {
-                    ReadOnlyMemory<byte> pkcs1 = KeyFormatHelper.ReadSubjectPublicKeyInfo(
-                        s_validOids,
+                    ReadOnlyMemory<byte> pkcs1 = RSAKeyFormatHelper.ReadSubjectPublicKeyInfo(
                         manager.Memory,
                         out int localRead);
 
@@ -587,18 +500,15 @@ namespace System.Security.Cryptography
             {
                 using (MemoryManager<byte> manager = new PointerMemoryManager<byte>(ptr, source.Length))
                 {
-                    RSAPublicKey key = AsnSerializer.Deserialize<RSAPublicKey>(
-                        manager.Memory,
-                        AsnEncodingRules.BER,
-                        out int localRead);
+                    AsnReader reader = new AsnReader(manager.Memory, AsnEncodingRules.BER);
+                    ReadOnlyMemory<byte> firstValue = reader.PeekEncodedValue();
+                    int localRead = firstValue.Length;
 
-                    RSAParameters rsaParameters = new RSAParameters
-                    {
-                        Modulus = key.Modulus.ToByteArray(isUnsigned: true, isBigEndian: true),
-                        Exponent = key.PublicExponent.ToByteArray(isUnsigned: true, isBigEndian: true),
-                    };
+                    AlgorithmIdentifierAsn ignored = default;
+                    RSAKeyFormatHelper.ReadRsaPublicKey(firstValue, ignored, out RSAParameters rsaParameters);
 
                     ImportParameters(rsaParameters);
+
                     bytesRead = localRead;
                 }
             }
@@ -610,14 +520,12 @@ namespace System.Security.Cryptography
             {
                 using (MemoryManager<byte> manager = new PointerMemoryManager<byte>(ptr, source.Length))
                 {
-                    RSAPrivateKeyAsn key =
-                        AsnSerializer.Deserialize<RSAPrivateKeyAsn>(
-                            manager.Memory,
-                            AsnEncodingRules.BER,
-                            out int localRead);
+                    AsnReader reader = new AsnReader(manager.Memory, AsnEncodingRules.BER);
+                    ReadOnlyMemory<byte> firstValue = reader.PeekEncodedValue();
+                    int localRead = firstValue.Length;
 
                     AlgorithmIdentifierAsn ignored = default;
-                    FromPkcs1PrivateKey(key, ignored, out RSAParameters rsaParameters);
+                    RSAKeyFormatHelper.FromPkcs1PrivateKey(firstValue, ignored, out RSAParameters rsaParameters);
 
                     fixed (byte* dPin = rsaParameters.D)
                     fixed (byte* pPin = rsaParameters.P)
@@ -647,8 +555,7 @@ namespace System.Security.Cryptography
             {
                 using (MemoryManager<byte> manager = new PointerMemoryManager<byte>(ptr, source.Length))
                 {
-                    ReadOnlyMemory<byte> pkcs1 = KeyFormatHelper.ReadPkcs8(
-                        s_validOids,
+                    ReadOnlyMemory<byte> pkcs1 = RSAKeyFormatHelper.ReadPkcs8(
                         manager.Memory,
                         out int localRead);
 
@@ -663,11 +570,9 @@ namespace System.Security.Cryptography
             ReadOnlySpan<byte> source,
             out int bytesRead)
         {
-            KeyFormatHelper.ReadEncryptedPkcs8<RSAParameters, RSAPrivateKeyAsn>(
-                s_validOids,
+            RSAKeyFormatHelper.ReadEncryptedPkcs8(
                 source,
                 passwordBytes,
-                FromPkcs1PrivateKey,
                 out int localRead,
                 out RSAParameters ret);
 
@@ -696,11 +601,9 @@ namespace System.Security.Cryptography
             ReadOnlySpan<byte> source,
             out int bytesRead)
         {
-            KeyFormatHelper.ReadEncryptedPkcs8<RSAParameters, RSAPrivateKeyAsn>(
-                s_validOids,
+            RSAKeyFormatHelper.ReadEncryptedPkcs8(
                 source,
                 password,
-                FromPkcs1PrivateKey,
                 out int localRead,
                 out RSAParameters ret);
 
@@ -724,44 +627,6 @@ namespace System.Security.Cryptography
             bytesRead = localRead;
         }
 
-        private static void FromPkcs1PrivateKey(
-            in RSAPrivateKeyAsn key,
-            in AlgorithmIdentifierAsn algId,
-            out RSAParameters ret)
-        {
-            if (!algId.HasNullEquivalentParameters())
-            {
-                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
-            }
-
-            const int MaxSupportedVersion = 0;
-
-            if (key.Version > MaxSupportedVersion)
-            {
-                throw new CryptographicException(
-                    SR.Format(
-                        SR.Cryptography_RSAPrivateKey_VersionTooNew,
-                        key.Version,
-                        MaxSupportedVersion));
-            }
-
-            // The modulus size determines the encoded output size of the CRT parameters.
-            byte[] n = key.Modulus.ToByteArray(isUnsigned: true, isBigEndian: true);
-            int halfModulusLength = (n.Length + 1) / 2;
-
-            ret = new RSAParameters
-            {
-                Modulus = n,
-                Exponent = key.PublicExponent.ToByteArray(isUnsigned: true, isBigEndian: true),
-                D = key.PrivateExponent.ExportKeyParameter(n.Length),
-                P = key.Prime1.ExportKeyParameter(halfModulusLength),
-                Q = key.Prime2.ExportKeyParameter(halfModulusLength),
-                DP = key.Exponent1.ExportKeyParameter(halfModulusLength),
-                DQ = key.Exponent2.ExportKeyParameter(halfModulusLength),
-                InverseQ = key.Coefficient.ExportKeyParameter(halfModulusLength),
-            };
-        }
-
         private static void ClearPrivateParameters(in RSAParameters rsaParameters)
         {
             CryptographicOperations.ZeroMemory(rsaParameters.D);
index e4a76ba..372450e 100644 (file)
   <data name="Cryptography_Asn_UnusedBitCountRange" xml:space="preserve">
     <value>Unused bit count must be between 0 and 7, inclusive.</value>
   </data>
-  <data name="Cryptography_AsnSerializer_AmbiguousFieldType" xml:space="preserve">
-    <value>Field '{0}' of type '{1}' has ambiguous type '{2}', an attribute derived from AsnTypeAttribute is required.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_Choice_AllowNullNonNullable" xml:space="preserve">
-    <value>[Choice].AllowNull=true is not valid because type '{0}' cannot have a null value.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_Choice_ConflictingTagMapping" xml:space="preserve">
-    <value>The tag ({0} {1}) for field '{2}' on type '{3}' already is associated in this context with field '{4}' on type '{5}'.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_Choice_DefaultValueDisallowed" xml:space="preserve">
-    <value>Field '{0}' on [Choice] type '{1}' has a default value, which is not permitted.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_Choice_NoChoiceWasMade" xml:space="preserve">
-    <value>An instance of [Choice] type '{0}' has no non-null fields.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_Choice_NonNullableField" xml:space="preserve">
-    <value>Field '{0}' on [Choice] type '{1}' can not be assigned a null value.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_Choice_TooManyValues" xml:space="preserve">
-    <value>Fields '{0}' and '{1}' on type '{2}' are both non-null when only one value is permitted.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_Choice_TypeCycle" xml:space="preserve">
-    <value>Field '{0}' on [Choice] type '{1}' has introduced a type chain cycle.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_MultipleAsnTypeAttributes" xml:space="preserve">
-    <value>Field '{0}' on type '{1}' has multiple attributes deriving from '{2}' when at most one is permitted.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_NoJaggedArrays" xml:space="preserve">
-    <value>Type '{0}' cannot be serialized or deserialized because it is an array of arrays.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_NoMultiDimensionalArrays" xml:space="preserve">
-    <value>Type '{0}' cannot be serialized or deserialized because it is a multi-dimensional array.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_NoOpenTypes" xml:space="preserve">
-    <value>Type '{0}' cannot be serialized or deserialized because it is not sealed or has unbound generic parameters.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_Optional_NonNullableField" xml:space="preserve">
-    <value>Field '{0}' on type '{1}' is declared [OptionalValue], but it can not be assigned a null value.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_PopulateFriendlyNameOnString" xml:space="preserve">
-    <value>Field '{0}' on type '{1}' has [ObjectIdentifier].PopulateFriendlyName set to true, which is not applicable to a string.  Change the field to '{2}' or set PopulateFriendlyName to false.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_SetValueException" xml:space="preserve">
-    <value>Unable to set field {0} on type {1}.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_SpecificTagChoice" xml:space="preserve">
-    <value>Field '{0}' on type '{1}' has specified an implicit tag value via [ExpectedTag] for [Choice] type '{2}'. ExplicitTag must be true, or the [ExpectedTag] attribute removed.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_UnexpectedTypeForAttribute" xml:space="preserve">
-    <value>Field '{0}' of type '{1}' has an effective type of '{2}' when one of ({3}) was expected.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_UtcTimeTwoDigitYearMaxTooSmall" xml:space="preserve">
-    <value>Field '{0}' on type '{1}' has a [UtcTime] TwoDigitYearMax value ({2}) smaller than the minimum (99).</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_UnhandledType" xml:space="preserve">
-    <value>Could not determine how to serialize or deserialize type '{0}'.</value>
-  </data>
   <data name="Cryptography_AsnWriter_EncodeUnbalancedStack" xml:space="preserve">
     <value>Encode cannot be called while a Sequence or SetOf is still open.</value>
   </data>
index 8a18ede..d533421 100644 (file)
@@ -16,6 +16,7 @@
     <AssemblyVersion Condition="'$(TargetGroup)' == 'netstandard1.4'">4.1.0.0</AssemblyVersion>
     <AssemblyVersion Condition="'$(TargetGroup)' == 'netstandard'">4.3.0.0</AssemblyVersion>
   </PropertyGroup>
+  <Import Project="$(CommonPath)\System\Security\Cryptography\Asn1\AsnXml.targets"/>
   <ItemGroup Condition="'$(IsPartialFacadeAssembly)' != 'true' AND '$(TargetsWindows)' == 'true'">
     <Compile Include="System\Security\Cryptography\AesCng.cs" />
     <Compile Include="System\Security\Cryptography\CngAlgorithm.cs" />
     <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1V2.cs">
       <Link>Common\System\Security\Cryptography\Asn1V2.cs</Link>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1V2.Serializer.cs">
-      <Link>Common\System\Security\Cryptography\Asn1V2.Serializer.cs</Link>
-    </Compile>
     <Compile Include="$(CommonPath)\System\Security\Cryptography\AsnReader.cs">
       <Link>Common\System\Security\Cryptography\AsnReader.cs</Link>
     </Compile>
     <Compile Include="$(CommonPath)\System\Security\Cryptography\RsaPaddingProcessor.cs">
       <Link>Common\System\Security\Cryptography\RsaPaddingProcessor.cs</Link>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.cs">
-      <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.cs</Link>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml</DependentUpon>
+    </Compile>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.manual.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.manual.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml</DependentUpon>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AttributeAsn.cs">
-      <Link>Common\System\Security\Cryptography\Asn1\AttributeAsn.cs</Link>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\AttributeAsn.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\AttributeAsn.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AttributeAsn.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\AttributeAsn.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\AttributeAsn.xml</DependentUpon>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBEParameter.cs">
-      <Link>Common\System\Security\Cryptography\Asn1\PBEParameter.cs</Link>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBEParameter.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\PBEParameter.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBEParameter.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\PBEParameter.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\PBEParameter.xml</DependentUpon>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBES2Params.cs">
-      <Link>Common\System\Security\Cryptography\Asn1\PBES2Params.cs</Link>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBES2Params.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\PBES2Params.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBES2Params.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\PBES2Params.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\PBES2Params.xml</DependentUpon>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2Params.cs">
-      <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2Params.cs</Link>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2Params.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2Params.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2Params.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2Params.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\Pbkdf2Params.xml</DependentUpon>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.cs">
-      <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.cs</Link>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml</DependentUpon>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.cs">
-      <Link>Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.cs</Link>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml</DependentUpon>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.cs">
-      <Link>Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.cs</Link>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml</DependentUpon>
     </Compile>
     <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml">
       <Link>Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml</Link>
       <Link>Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.manual.cs</Link>
       <DependentUpon>Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml</DependentUpon>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.cs">
-      <Link>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.cs</Link>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml</DependentUpon>
     </Compile>
   </ItemGroup>
+  <ItemGroup>
+    <None Include="@(AsnXml)" /> 
+  </ItemGroup>
   <ItemGroup Condition="'$(IsPartialFacadeAssembly)' == 'true'">
     <Reference Include="mscorlib" />
     <Reference Include="System.Core" />
index 4801ed8..a7b956f 100644 (file)
@@ -911,4 +911,35 @@ namespace System.Security.Cryptography.Tests.Asn1
         [Integer]
         public ReadOnlyMemory<byte> Second;
     }
+
+    // https://tools.ietf.org/html/rfc3280#section-4.1.1.2
+    //
+    // AlgorithmIdentifier  ::=  SEQUENCE  {
+    //   algorithm OBJECT IDENTIFIER,
+    //   parameters ANY DEFINED BY algorithm OPTIONAL  }
+    [StructLayout(LayoutKind.Sequential)]
+    internal partial struct AlgorithmIdentifierAsn
+    {
+        internal static readonly ReadOnlyMemory<byte> ExplicitDerNull = new byte[] { 0x05, 0x00 };
+
+        [ObjectIdentifier(PopulateFriendlyName = true)]
+        public Oid Algorithm;
+
+        [AnyValue, OptionalValue]
+        public ReadOnlyMemory<byte>? Parameters;
+    }
+
+    // https://tools.ietf.org/html/rfc3280#section-4.1
+    //
+    // SubjectPublicKeyInfo  ::=  SEQUENCE  {
+    //   algorithm            AlgorithmIdentifier,
+    //   subjectPublicKey     BIT STRING  }
+    [StructLayout(LayoutKind.Sequential)]
+    internal partial struct SubjectPublicKeyInfoAsn
+    {
+        internal AlgorithmIdentifierAsn Algorithm;
+
+        [BitString]
+        internal ReadOnlyMemory<byte> SubjectPublicKey;
+    }
 }
index a9482f1..44818f7 100644 (file)
     <Compile Include="$(CommonPath)\System\Security\Cryptography\DerSequenceReader.cs">
       <Link>Common\System\Security\Cryptography\DerSequenceReader.cs</Link>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.cs">
-      <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.cs</Link>
-    </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.cs">
-      <Link>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.cs</Link>
-    </Compile>
     <Compile Include="$(CommonTestPath)\System\Security\Cryptography\ByteUtils.cs">
       <Link>CommonTest\System\Security\Cryptography\ByteUtils.cs</Link>
     </Compile>
index 99aadc3..429ea8f 100644 (file)
   <data name="Cryptography_SignHash_WrongSize" xml:space="preserve">
     <value>The provided hash value is not the expected size for the specified hash algorithm.</value>
   </data>
+  <data name="Cryptography_WriteEncodedValue_OneValueAtATime" xml:space="preserve">
+    <value>The input to WriteEncodedValue must represent a single encoded value with no trailing data.</value>
+  </data>
+  <data name="Cryptography_Asn_EnumeratedValueRequiresNonFlagsEnum" xml:space="preserve">
+    <value>ASN.1 Enumerated values only apply to enum types without the [Flags] attribute.</value>
+  </data>
+  <data name="Cryptography_Asn_NamedBitListRequiresFlagsEnum" xml:space="preserve">
+    <value>Named bit list operations require an enum with the [Flags] attribute.</value>
+  </data>
+  <data name="Cryptography_Asn_NamedBitListValueTooBig" xml:space="preserve">
+    <value>The encoded named bit list value is larger than the value size of the '{0}' enum.</value>
+  </data>
+  <data name="Cryptography_Asn_UniversalValueIsFixed" xml:space="preserve">
+    <value>Tags with TagClass Universal must have the appropriate TagValue value for the data type being read or written.</value>
+  </data>
+  <data name="Cryptography_Asn_UnusedBitCountRange" xml:space="preserve">
+    <value>Unused bit count must be between 0 and 7, inclusive.</value>
+  </data>
+  <data name="Cryptography_AsnWriter_EncodeUnbalancedStack" xml:space="preserve">
+    <value>Encode cannot be called while a Sequence or SetOf is still open.</value>
+  </data>
+  <data name="Cryptography_AsnWriter_PopWrongTag" xml:space="preserve">
+    <value>Cannot pop the requested tag as it is not currently in progress.</value>
+  </data>
+  <data name="Cryptography_NotValidPublicOrPrivateKey" xml:space="preserve">
+    <value>Key is not a valid public or private key.</value>
+  </data>
   <data name="PlatformNotSupported_CryptographyOpenSSL" xml:space="preserve">
     <value>OpenSSL is not supported on this platform.</value>
   </data>
index ffadbb7..a89fc60 100644 (file)
@@ -5,6 +5,7 @@
     <AssemblyName>System.Security.Cryptography.OpenSsl</AssemblyName>
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
     <AssemblyVersion Condition="'$(TargetGroup)' == 'netstandard'">4.1.0.0</AssemblyVersion>
+    <DefineConstants Condition="'$(TargetGroup)' == 'netcoreapp'">$(DefineConstants);netcoreapp</DefineConstants>
     <Configurations>netcoreapp-Debug;netcoreapp-Release;netcoreapp-Unix-Debug;netcoreapp-Unix-Release;netstandard-Debug;netstandard-Release</Configurations>
   </PropertyGroup>
   <PropertyGroup Condition="'$(TargetsUnix)' != 'true'">
     <Compile Include="$(CommonPath)\Microsoft\Win32\SafeHandles\SafeEvpPKeyHandle.Unix.cs">
       <Link>Common\Microsoft\Win32\SafeHandles\SafeEvpPKeyHandle.Unix.cs</Link>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\DerEncoder.cs">
-      <Link>Common\System\Security\Cryptography\DerEncoder.cs</Link>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1V2.cs">
+      <Link>Common\System\Security\Cryptography\Asn1V2.cs</Link>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\DerSequenceReader.cs">
-      <Link>Common\System\Security\Cryptography\DerSequenceReader.cs</Link>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\AsnReader.cs">
+      <Link>Common\System\Security\Cryptography\AsnReader.cs</Link>
+    </Compile>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\AsnWriter.cs">
+      <Link>Common\System\Security\Cryptography\AsnWriter.cs</Link>
     </Compile>
     <Compile Include="$(CommonPath)\System\Security\Cryptography\DSAOpenSsl.cs">
       <Link>Common\System\Security\Cryptography\DSAOpenSsl.cs</Link>
     <Compile Include="$(CommonPath)\System\Security\Cryptography\ECOpenSsl.ImportExport.cs">
       <Link>Common\System\Security\Cryptography\ECOpenSsl.ImportExport.cs</Link>
     </Compile>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\KeyBlobHelpers.cs">
+      <Link>Common\System\Security\Cryptography\KeyBlobHelpers.cs</Link>
+    </Compile>
     <Compile Include="$(CommonPath)\System\Security\Cryptography\RSAOpenSsl.cs">
       <Link>Common\System\Security\Cryptography\RSAOpenSsl.cs</Link>
     </Compile>
index c5fd89a..4029810 100644 (file)
     <Compile Include="$(CommonPath)\System\Security\Cryptography\Oids.cs">
       <Link>Common\System\Security\Cryptography\Oids.cs</Link>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.cs">
-      <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.cs</Link>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml</DependentUpon>
+    </Compile>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.manual.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.manual.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml</DependentUpon>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AttributeAsn.cs">
-      <Link>Common\System\Security\Cryptography\Asn1\AttributeAsn.cs</Link>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\AttributeAsn.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\AttributeAsn.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AttributeAsn.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\AttributeAsn.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\AttributeAsn.xml</DependentUpon>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.cs">
-      <Link>Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.cs</Link>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml</DependentUpon>
     </Compile>
     <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\DirectoryStringAsn.xml">
       <Link>Common\System\Security\Cryptography\Asn1\DirectoryStringAsn.xml</Link>
       <Link>Common\System\Security\Cryptography\Asn1\OtherNameAsn.xml.cs</Link>
       <DependentUpon>Common\System\Security\Cryptography\Asn1\OtherNameAsn.xml</DependentUpon>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBEParameter.cs">
-      <Link>Common\System\Security\Cryptography\Asn1\PBEParameter.cs</Link>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBEParameter.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\PBEParameter.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBEParameter.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\PBEParameter.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\PBEParameter.xml</DependentUpon>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBES2Params.cs">
-      <Link>Common\System\Security\Cryptography\Asn1\PBES2Params.cs</Link>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBES2Params.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\PBES2Params.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBES2Params.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\PBES2Params.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\PBES2Params.xml</DependentUpon>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2Params.cs">
-      <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2Params.cs</Link>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2Params.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2Params.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2Params.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2Params.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\Pbkdf2Params.xml</DependentUpon>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.cs">
-      <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.cs</Link>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml</DependentUpon>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PssParamsAsn.cs">
-      <Link>Common\System\Security\Cryptography\Asn1\PssParamsAsn.cs</Link>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\PssParamsAsn.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\PssParamsAsn.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PssParamsAsn.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\PssParamsAsn.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\PssParamsAsn.xml</DependentUpon>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.cs">
-      <Link>Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.cs</Link>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml</DependentUpon>
     </Compile>
     <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml">
       <Link>Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml</Link>
       <Link>Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.manual.cs</Link>
       <DependentUpon>Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml</DependentUpon>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.cs">
-      <Link>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.cs</Link>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml</DependentUpon>
     </Compile>
     <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\X509ExtensionAsn.cs">
       <Link>Common\System\Security\Cryptography\Asn1\X509ExtensionAsn.cs</Link>
index 7688c07..5cf002f 100644 (file)
@@ -298,7 +298,6 @@ namespace System.Security.Cryptography.Pkcs.Tests
         {
             Assert.NotSame(expected.Oid, actual.Oid);
             Assert.Equal(expected.Oid.Value, actual.Oid.Value);
-            Assert.Equal(expected.Oid.FriendlyName, actual.Oid.FriendlyName);
 
             // We need to decode bytes because DER and BER may encode the same information slightly differently
             Rfc3161TimestampTokenInfo expectedToken;
index 84c71f0..b195c12 100644 (file)
@@ -4,8 +4,10 @@
 
 using System;
 using System.Diagnostics;
+using System.Numerics;
 using System.Security.Cryptography;
 using System.Security.Cryptography.Apple;
+using System.Security.Cryptography.Asn1;
 using System.Security.Cryptography.X509Certificates;
 
 namespace Internal.Cryptography.Pal
@@ -82,9 +84,11 @@ namespace Internal.Cryptography.Pal
 
             private static AsymmetricAlgorithm DecodeRsaPublicKey(byte[] encodedKeyValue)
             {
-                DerSequenceReader reader = new DerSequenceReader(encodedKeyValue);
-                RSAParameters rsaParameters = new RSAParameters();
-                reader.ReadPkcs1PublicBlob(ref rsaParameters);
+                AlgorithmIdentifierAsn ignored = default;
+                RSAKeyFormatHelper.ReadRsaPublicKey(
+                    encodedKeyValue,
+                    ignored,
+                    out RSAParameters rsaParameters);
 
                 RSA rsa = RSA.Create();
                 try
@@ -101,10 +105,10 @@ namespace Internal.Cryptography.Pal
 
             private static AsymmetricAlgorithm DecodeDsaPublicKey(byte[] encodedKeyValue, byte[] encodedParameters)
             {
-                DSAParameters dsaParameters = new DSAParameters();
-                DerSequenceReader parameterReader = new DerSequenceReader(encodedParameters);
-
-                parameterReader.ReadSubjectPublicKeyInfo(encodedKeyValue, ref dsaParameters);
+                DSAKeyFormatHelper.ReadDsaPublicKey(
+                    encodedKeyValue,
+                    new AlgorithmIdentifierAsn { Parameters = encodedParameters },
+                    out DSAParameters dsaParameters);
 
                 DSA dsa = DSA.Create();
                 try
index ba0f94b..e6a93c8 100644 (file)
   <data name="Cryptography_AsnWriter_PopWrongTag" xml:space="preserve">
     <value>Cannot pop the requested tag as it is not currently in progress.</value>
   </data>
+  <data name="Cryptography_NotValidPublicOrPrivateKey" xml:space="preserve">
+    <value>Key is not a valid public or private key.</value>
+  </data>
+  <data name="Cryptography_Pkcs8_EncryptedReadFailed" xml:space="preserve">
+    <value>The EncryptedPrivateKeyInfo structure was decoded but was not successfully interpreted, the password may be incorrect.</value>
+  </data>
+  <data name="Cryptography_UnknownAlgorithmIdentifier" xml:space="preserve">
+    <value>The algorithm identified by '{0}' is unknown, not valid for the requested usage, or was not handled.</value>
+  </data>
+  <data name="Argument_InvalidValue" xml:space="preserve">
+    <value>Value was invalid.</value>
+  </data>
+  <data name="Cryptography_AlgKdfRequiresChars" xml:space="preserve">
+    <value>The KDF for algorithm '{0}' requires a char-based password input.</value>
+  </data>
+  <data name="Cryptography_RSAPrivateKey_VersionTooNew" xml:space="preserve">
+    <value>The provided RSAPrivateKey value has version '{0}', but version '{1}' is the maximum supported.</value>
+  </data>
+  <data name="Cryptography_NotValidPrivateKey" xml:space="preserve">
+    <value>Key is not a valid private key.</value>
+  </data>
 </root>
index ffc99bb..db54b57 100644 (file)
     <Compile Include="$(CommonPath)\System\Security\Cryptography\Oids.cs">
       <Link>Common\System\Security\Cryptography\Oids.cs</Link>
     </Compile>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\KeyBlobHelpers.cs">
+      <Link>Common\System\Security\Cryptography\KeyBlobHelpers.cs</Link>
+    </Compile>
     <Compile Include="$(CommonPath)\System\Security\Cryptography\KeySizeHelpers.cs">
       <Link>Common\System\Security\Cryptography\KeySizeHelpers.cs</Link>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.cs">
-      <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.cs</Link>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml</DependentUpon>
+    </Compile>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.manual.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.manual.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml</DependentUpon>
     </Compile>
     <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\DirectoryStringAsn.xml">
       <Link>Common\System\Security\Cryptography\Asn1\DirectoryStringAsn.xml</Link>
       <Link>Common\System\Security\Cryptography\Asn1\OtherNameAsn.xml.cs</Link>
       <DependentUpon>Common\System\Security\Cryptography\Asn1\OtherNameAsn.xml</DependentUpon>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PssParamsAsn.cs">
-      <Link>Common\System\Security\Cryptography\Asn1\PssParamsAsn.cs</Link>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\PssParamsAsn.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\PssParamsAsn.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PssParamsAsn.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\PssParamsAsn.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\PssParamsAsn.xml</DependentUpon>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.cs">
-      <Link>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.cs</Link>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml</DependentUpon>
     </Compile>
     <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\X509ExtensionAsn.cs">
       <Link>Common\System\Security\Cryptography\Asn1\X509ExtensionAsn.cs</Link>
     </Compile>
+    <Compile Include="$(CommonPath)\Internal\Cryptography\AsymmetricAlgorithmHelpers.Der.cs">
+      <Link>Common\Internal\Cryptography\AsymmetricAlgorithmHelpers.Der.cs</Link>
+    </Compile>
     <Compile Include="$(CommonPath)\Internal\Cryptography\Helpers.cs">
       <Link>Internal\Cryptography\Helpers.cs</Link>
     </Compile>
     </Compile>
   </ItemGroup>
   <ItemGroup Condition=" '$(TargetsOSX)' == 'true' AND '$(IsPartialFacadeAssembly)' != 'true'">
-    <Compile Include="$(CommonPath)\Internal\Cryptography\AsymmetricAlgorithmHelpers.Der.cs">
-      <Link>Common\Internal\Cryptography\AsymmetricAlgorithmHelpers.Der.cs</Link>
-    </Compile>
     <Compile Include="$(CommonPath)\Internal\Cryptography\AsymmetricAlgorithmHelpers.Hash.cs">
       <Link>Common\Internal\Cryptography\AsymmetricAlgorithmHelpers.Hash.cs</Link>
     </Compile>
     <Compile Include="$(CommonPath)\Microsoft\Win32\SafeHandles\SafeCreateHandle.OSX.cs">
       <Link>Common\Microsoft\Win32\SafeHandles\SafeCreateHandle.OSX.cs</Link>
     </Compile>
+    <Compile Include="$(CommonPath)\System\Memory\PointerMemoryManager.cs">
+      <Link>Common\System\Memory\PointerMemoryManager.cs</Link>
+    </Compile>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\DSAKeyFormatHelper.cs">
+      <Link>Common\System\Security\Cryptography\DSAKeyFormatHelper.cs</Link>
+    </Compile>
     <Compile Include="$(CommonPath)\System\Security\Cryptography\DSASecurityTransforms.cs">
       <Link>Common\System\Security\Cryptography\DSASecurityTransforms.cs</Link>
     </Compile>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\EccKeyFormatHelper.cs">
+      <Link>Common\System\Security\Cryptography\EccKeyFormatHelper.cs</Link>
+    </Compile>
     <Compile Include="$(CommonPath)\System\Security\Cryptography\EccSecurityTransforms.cs">
       <Link>Common\System\Security\Cryptography\EccSecurityTransforms.cs</Link>
     </Compile>
     <Compile Include="$(CommonPath)\System\Security\Cryptography\ECDsaSecurityTransforms.cs">
       <Link>Common\System\Security\Cryptography\ECDsaSecurityTransforms.cs</Link>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\KeyBlobHelpers.cs">
-      <Link>Common\System\Security\Cryptography\KeyBlobHelpers.cs</Link>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\KeyFormatHelper.cs">
+      <Link>Common\System\Security\Cryptography\KeyFormatHelper.cs</Link>
+    </Compile>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\PasswordBasedEncryption.cs">
+      <Link>Common\System\Security\Cryptography\PasswordBasedEncryption.cs</Link>
+    </Compile>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Pkcs12Kdf.cs">
+      <Link>Common\System\Security\Cryptography\Pkcs12Kdf.cs</Link>
+    </Compile>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\RSAKeyFormatHelper.cs">
+      <Link>Common\System\Security\Cryptography\RSAKeyFormatHelper.cs</Link>
     </Compile>
     <Compile Include="$(CommonPath)\System\Security\Cryptography\RsaPaddingProcessor.cs">
       <Link>Common\System\Security\Cryptography\RsaPaddingProcessor.cs</Link>
     <Compile Include="$(CommonPath)\System\Security\Cryptography\SecKeyPair.cs">
       <Link>Common\System\Security\Cryptography\SecKeyPair.cs</Link>
     </Compile>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\AttributeAsn.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\AttributeAsn.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AttributeAsn.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\AttributeAsn.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\AttributeAsn.xml</DependentUpon>
+    </Compile>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\CurveAsn.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\CurveAsn.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\CurveAsn.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\CurveAsn.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\CurveAsn.xml</DependentUpon>
+    </Compile>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\DssParms.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\DssParms.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\DssParms.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\DssParms.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\DssParms.xml</DependentUpon>
+    </Compile>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\ECDomainParameters.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\ECDomainParameters.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\ECDomainParameters.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\ECDomainParameters.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\ECDomainParameters.xml</DependentUpon>
+    </Compile>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\ECPrivateKey.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\ECPrivateKey.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\ECPrivateKey.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\ECPrivateKey.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\ECPrivateKey.xml</DependentUpon>
+    </Compile>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml</DependentUpon>
+    </Compile>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\FieldID.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\FieldID.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\FieldID.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\FieldID.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\FieldID.xml</DependentUpon>
+    </Compile>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml</DependentUpon>
+    </Compile>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBEParameter.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\PBEParameter.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBEParameter.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\PBEParameter.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\PBEParameter.xml</DependentUpon>
+    </Compile>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBES2Params.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\PBES2Params.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBES2Params.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\PBES2Params.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\PBES2Params.xml</DependentUpon>
+    </Compile>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2Params.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2Params.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2Params.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2Params.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\Pbkdf2Params.xml</DependentUpon>
+    </Compile>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml</DependentUpon>
+    </Compile>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml</DependentUpon>
+    </Compile>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\Rc2CbcParameters.manual.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.manual.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml</DependentUpon>
+    </Compile>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\RSAPrivateKeyAsn.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\RSAPrivateKeyAsn.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\RSAPrivateKeyAsn.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\RSAPrivateKeyAsn.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\RSAPrivateKeyAsn.xml</DependentUpon>
+    </Compile>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\RSAPublicKeyAsn.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\RSAPublicKeyAsn.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\RSAPublicKeyAsn.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\RSAPublicKeyAsn.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\RSAPublicKeyAsn.xml</DependentUpon>
+    </Compile>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\SpecifiedECDomain.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\SpecifiedECDomain.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\SpecifiedECDomain.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\SpecifiedECDomain.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\SpecifiedECDomain.xml</DependentUpon>
+    </Compile>
     <Compile Include="Internal\Cryptography\Pal.OSX\AppleCertificatePal.cs" />
     <Compile Include="Internal\Cryptography\Pal.OSX\CertificatePal.cs" />
     <Compile Include="Internal\Cryptography\Pal.OSX\CertificateData.cs" />
index 4cf69a3..2890645 100644 (file)
@@ -3,6 +3,8 @@
 // See the LICENSE file in the project root for more information.
 
 using System.Diagnostics;
+using System.Numerics;
+using System.Security.Cryptography.Asn1;
 using Internal.Cryptography;
 
 namespace System.Security.Cryptography.X509Certificates
@@ -42,19 +44,19 @@ namespace System.Security.Cryptography.X509Certificates
                     SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name));
             }
 
-            return DerEncoder.ConstructSequence(DerEncoder.SegmentedEncodeOid(oid));
+            using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER))
+            {
+                writer.PushSequence();
+                writer.WriteObjectIdentifier(oid);
+                writer.PopSequence();
+                return writer.Encode();
+            }
         }
 
         public override byte[] SignData(byte[] data, HashAlgorithmName hashAlgorithm)
         {
             byte[] ieeeFormat = _key.SignData(data, hashAlgorithm);
-
-            Debug.Assert(ieeeFormat.Length % 2 == 0);
-            int segmentLength = ieeeFormat.Length / 2;
-
-            return DerEncoder.ConstructSequence(
-                DerEncoder.SegmentedEncodeUnsignedInteger(new ReadOnlySpan<byte>(ieeeFormat, 0, segmentLength)),
-                DerEncoder.SegmentedEncodeUnsignedInteger(new ReadOnlySpan<byte>(ieeeFormat, segmentLength, segmentLength)));
+            return AsymmetricAlgorithmHelpers.ConvertIeee1363ToDer(ieeeFormat);
         }
 
         protected override PublicKey BuildPublicKey()
@@ -67,6 +69,7 @@ namespace System.Security.Cryptography.X509Certificates
             }
 
             string curveOid = ecParameters.Curve.Oid.Value;
+            byte[] curveOidEncoded;
 
             if (string.IsNullOrEmpty(curveOid))
             {
@@ -91,6 +94,12 @@ namespace System.Security.Cryptography.X509Certificates
                 }
             }
 
+            using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER))
+            {
+                writer.WriteObjectIdentifier(curveOid);
+                curveOidEncoded = writer.Encode();
+            }
+
             Debug.Assert(ecParameters.Q.X.Length == ecParameters.Q.Y.Length);
             byte[] uncompressedPoint = new byte[1 + ecParameters.Q.X.Length + ecParameters.Q.Y.Length];
 
@@ -104,7 +113,7 @@ namespace System.Security.Cryptography.X509Certificates
             
             return new PublicKey(
                 ecPublicKey,
-                new AsnEncodedData(ecPublicKey, DerEncoder.EncodeOid(curveOid)),
+                new AsnEncodedData(ecPublicKey, curveOidEncoded),
                 new AsnEncodedData(ecPublicKey, uncompressedPoint));
         }
     }
index e1d499b..0fa48fa 100644 (file)
@@ -3,6 +3,7 @@
 // See the LICENSE file in the project root for more information.
 
 using System.Diagnostics;
+using System.Security.Cryptography.Asn1;
 using Internal.Cryptography;
 
 namespace System.Security.Cryptography.X509Certificates
@@ -30,12 +31,6 @@ namespace System.Security.Cryptography.X509Certificates
 
         internal static PublicKey BuildPublicKey(RSA rsa)
         {
-            RSAParameters parameters = rsa.ExportParameters(false);
-
-            byte[] rsaPublicKey = DerEncoder.ConstructSequence(
-                DerEncoder.SegmentedEncodeUnsignedInteger(parameters.Modulus),
-                DerEncoder.SegmentedEncodeUnsignedInteger(parameters.Exponent));
-
             Oid oid = new Oid(Oids.Rsa);
 
             // The OID is being passed to everything here because that's what
@@ -47,7 +42,7 @@ namespace System.Security.Cryptography.X509Certificates
                 // This is due to one version of the ASN.1 not including OPTIONAL, and that was
                 // the version that got predominately implemented for RSA. Now it's convention.
                 new AsnEncodedData(oid, new byte[] { 0x05, 0x00 }),
-                new AsnEncodedData(oid, rsaPublicKey));
+                new AsnEncodedData(oid, rsa.ExportRSAPublicKey()));
         }
 
         public override byte[] GetSignatureAlgorithmIdentifier(HashAlgorithmName hashAlgorithm)
@@ -74,9 +69,14 @@ namespace System.Security.Cryptography.X509Certificates
                     SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name));
             }
 
-            return DerEncoder.ConstructSequence(
-                DerEncoder.SegmentedEncodeOid(oid),
-                DerEncoder.SegmentedEncodeNull());
+            using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER))
+            {
+                writer.PushSequence();
+                writer.WriteObjectIdentifier(oid);
+                writer.WriteNull();
+                writer.PopSequence();
+                return writer.Encode();
+            }
         }
     }
 }
index 2d651c5..7a01885 100644 (file)
@@ -34,7 +34,7 @@ namespace System.Security.Cryptography.X509Certificates
                 throw new CryptographicException(SR.Cryptography_InvalidPaddingMode);
             }
 
-            uint cbSalt;
+            int cbSalt;
             string digestOid;
 
             if (hashAlgorithm == HashAlgorithmName.SHA256)