Esempio n. 1
0
        private static List <X500RelativeDistinguishedName> ParseAttributes(byte[] rawData)
        {
            List <X500RelativeDistinguishedName>?parsedAttributes = null;
            ReadOnlyMemory <byte> rawDataMemory = rawData;
            ReadOnlySpan <byte>   rawDataSpan   = rawData;

            try
            {
                AsnValueReader outer    = new AsnValueReader(rawDataSpan, AsnEncodingRules.DER);
                AsnValueReader sequence = outer.ReadSequence();
                outer.ThrowIfNotEmpty();

                while (sequence.HasData)
                {
                    ReadOnlySpan <byte> encodedValue = sequence.PeekEncodedValue();

                    if (!rawDataSpan.Overlaps(encodedValue, out int offset))
                    {
                        Debug.Fail("AsnValueReader produced a span outside of the original bounds");
                        throw new UnreachableException();
                    }

                    var rdn = new X500RelativeDistinguishedName(rawDataMemory.Slice(offset, encodedValue.Length));
                    sequence.ReadEncodedValue();
                    (parsedAttributes ??= new List <X500RelativeDistinguishedName>()).Add(rdn);
                }
            }
            catch (AsnContentException e)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e);
            }

            return(parsedAttributes ?? new List <X500RelativeDistinguishedName>());
        }
Esempio n. 2
0
        public static Pkcs8PrivateKeyInfo Decode(
            ReadOnlyMemory <byte> source,
            out int bytesRead,
            bool skipCopy = false)
        {
            try
            {
                AsnValueReader reader = new AsnValueReader(source.Span, AsnEncodingRules.BER);
                // By using the default/empty ReadOnlyMemory value, the Decode method will have to
                // make copies of the data when assigning ReadOnlyMemory fields.
                ReadOnlyMemory <byte> rebind = skipCopy ? source : default;

                int localRead = reader.PeekEncodedValue().Length;
                PrivateKeyInfoAsn.Decode(ref reader, rebind, out PrivateKeyInfoAsn privateKeyInfo);
                bytesRead = localRead;

                return(new Pkcs8PrivateKeyInfo(
                           new Oid(privateKeyInfo.PrivateKeyAlgorithm.Algorithm, null),
                           privateKeyInfo.PrivateKeyAlgorithm.Parameters,
                           privateKeyInfo.PrivateKey,
                           SignerInfo.MakeAttributeCollection(privateKeyInfo.Attributes)));
            }
            catch (AsnContentException e)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e);
            }
        }
Esempio n. 3
0
        protected void ParsePkcs12(ReadOnlySpan <byte> data)
        {
            try
            {
                // RFC7292 specifies BER instead of DER
                AsnValueReader reader = new AsnValueReader(data, AsnEncodingRules.BER);

                // Windows compatibility: Ignore trailing data.
                ReadOnlySpan <byte> encodedData = reader.PeekEncodedValue();

                unsafe
                {
                    IntPtr      tmpPtr  = Marshal.AllocHGlobal(encodedData.Length);
                    Span <byte> tmpSpan = new Span <byte>((byte *)tmpPtr, encodedData.Length);
                    encodedData.CopyTo(tmpSpan);
                    _tmpManager = new PointerMemoryManager <byte>((void *)tmpPtr, encodedData.Length);
                }

                ReadOnlyMemory <byte> tmpMemory = _tmpManager.Memory;
                reader = new AsnValueReader(tmpMemory.Span, AsnEncodingRules.BER);

                PfxAsn.Decode(ref reader, tmpMemory, out PfxAsn pfxAsn);

                if (pfxAsn.AuthSafe.ContentType != Oids.Pkcs7Data)
                {
                    throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
                }

                _pfxAsn = pfxAsn;
            }
            catch (AsnContentException e)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e);
            }
        }
Esempio n. 4
0
        protected void ParsePkcs12(byte[] data)
        {
            try
            {
                // RFC7292 specifies BER instead of DER
                AsnValueReader      reader      = new AsnValueReader(data, AsnEncodingRules.BER);
                ReadOnlySpan <byte> encodedData = reader.PeekEncodedValue();

                // Windows compatibility: Ignore trailing data.
                if (encodedData.Length != data.Length)
                {
                    reader = new AsnValueReader(encodedData, AsnEncodingRules.BER);
                }

                PfxAsn.Decode(ref reader, data, out PfxAsn pfxAsn);

                if (pfxAsn.AuthSafe.ContentType != Oids.Pkcs7Data)
                {
                    throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
                }

                _pfxAsn = pfxAsn;
            }
            catch (AsnContentException e)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e);
            }
        }
Esempio n. 5
0
        private static unsafe int DecodeSubjectPublicKeyInfo(
            ReadOnlySpan <byte> source,
            out Oid oid,
            out AsnEncodedData parameters,
            out AsnEncodedData keyValue)
        {
            fixed(byte *ptr = &MemoryMarshal.GetReference(source))
            using (MemoryManager <byte> manager = new PointerMemoryManager <byte>(ptr, source.Length))
            {
                AsnValueReader reader = new AsnValueReader(source, AsnEncodingRules.DER);

                int read;
                SubjectPublicKeyInfoAsn spki;

                try
                {
                    read = reader.PeekEncodedValue().Length;
                    SubjectPublicKeyInfoAsn.Decode(ref reader, manager.Memory, out spki);
                }
                catch (AsnContentException e)
                {
                    throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e);
                }

                oid        = new Oid(spki.Algorithm.Algorithm, null);
                parameters = new AsnEncodedData(spki.Algorithm.Parameters?.ToArray() ?? Array.Empty <byte>());
                keyValue   = new AsnEncodedData(spki.SubjectPublicKey.ToArray());
                return(read);
            }
        }
        private static void ReadEncryptedPkcs8 <TRet>(
            string[] validOids,
            ReadOnlyMemory <byte> source,
            ReadOnlySpan <char> password,
            ReadOnlySpan <byte> passwordBytes,
            KeyReader <TRet> keyReader,
            out int bytesRead,
            out TRet ret)
        {
            int read;
            EncryptedPrivateKeyInfoAsn epki;

            try
            {
                AsnValueReader reader = new AsnValueReader(source.Span, AsnEncodingRules.BER);
                read = reader.PeekEncodedValue().Length;
                EncryptedPrivateKeyInfoAsn.Decode(ref reader, source, out epki);
            }
            catch (AsnContentException e)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e);
            }

            // No supported encryption algorithms produce more bytes of decryption output than there
            // were of decryption input.
            byte[]        decrypted       = CryptoPool.Rent(epki.EncryptedData.Length);
            Memory <byte> decryptedMemory = decrypted;

            try
            {
                int decryptedBytes = PasswordBasedEncryption.Decrypt(
                    epki.EncryptionAlgorithm,
                    password,
                    passwordBytes,
                    epki.EncryptedData.Span,
                    decrypted);

                decryptedMemory = decryptedMemory.Slice(0, decryptedBytes);

                ReadPkcs8(
                    validOids,
                    decryptedMemory,
                    keyReader,
                    out int innerRead,
                    out ret);

                if (innerRead != decryptedMemory.Length)
                {
                    ret = default !;
Esempio n. 7
0
        public static void PeekEncodedValue_InvalidLength()
        {
            byte[] badLength = "04040203".HexToByteArray();

            AsnReader reader = new AsnReader(badLength, AsnEncodingRules.BER);

            Assert.Throws <CryptographicException>(() => reader.PeekEncodedValue());
            Assert.Throws <CryptographicException>(() => reader.ReadEncodedValue());

            Assert.Throws <CryptographicException>(
                () =>
            {
                AsnValueReader valueReader = new AsnValueReader(badLength, AsnEncodingRules.BER);
                valueReader.PeekEncodedValue();
            });
            Assert.Throws <CryptographicException>(
                () =>
            {
                AsnValueReader valueReader = new AsnValueReader(badLength, AsnEncodingRules.BER);
                valueReader.ReadEncodedValue();
            });
        }
Esempio n. 8
0
        public static bool TryDecode(
            ReadOnlyMemory <byte> encodedBytes,
            [NotNullWhen(true)] out Rfc3161TimestampRequest?request,
            out int bytesConsumed)
        {
            try
            {
                // RFC 3161 doesn't have a concise statement that TimeStampReq will
                // be DER encoded, but under the email protocol (3.1), file protocol (3.2),
                // socket protocol (3.3) and HTTP protocol (3.4) they all say DER for the
                // transmission.
                //
                // Since nothing says BER, assume DER only.
                const AsnEncodingRules RuleSet = AsnEncodingRules.DER;

                AsnValueReader      reader       = new AsnValueReader(encodedBytes.Span, RuleSet);
                ReadOnlySpan <byte> firstElement = reader.PeekEncodedValue();

                Rfc3161TimeStampReq.Decode(ref reader, encodedBytes, out Rfc3161TimeStampReq req);

                request = new Rfc3161TimestampRequest
                {
                    _parsedData   = req,
                    _encodedBytes = firstElement.ToArray(),
                };

                bytesConsumed = firstElement.Length;
                return(true);
            }
            catch (CryptographicException)
            {
            }

            request       = null;
            bytesConsumed = 0;
            return(false);
        }
Esempio n. 9
0
        private bool ProcessResponse(
            ReadOnlyMemory <byte> source,
            [NotNullWhen(true)] out Rfc3161TimestampToken?token,
            out Rfc3161RequestResponseStatus status,
            out int bytesConsumed,
            bool shouldThrow)
        {
            status = Rfc3161RequestResponseStatus.Unknown;
            token  = null;

            Rfc3161TimeStampResp resp;

            try
            {
                AsnValueReader reader         = new AsnValueReader(source.Span, AsnEncodingRules.DER);
                int            localBytesRead = reader.PeekEncodedValue().Length;

                Rfc3161TimeStampResp.Decode(ref reader, source, out resp);
                bytesConsumed = localBytesRead;
            }
            catch (CryptographicException) when(!shouldThrow)
            {
                bytesConsumed = 0;
                status        = Rfc3161RequestResponseStatus.DoesNotParse;
                return(false);
            }

            // bytesRead will be set past this point

            PkiStatus pkiStatus = (PkiStatus)resp.Status.Status;

            if (pkiStatus != PkiStatus.Granted &&
                pkiStatus != PkiStatus.GrantedWithMods)
            {
                if (shouldThrow)
                {
                    throw new CryptographicException(
                              SR.Format(
                                  SR.Cryptography_TimestampReq_Failure,
                                  pkiStatus,
                                  resp.Status.FailInfo.GetValueOrDefault()));
                }

                status = Rfc3161RequestResponseStatus.RequestFailed;
                return(false);
            }

            if (!Rfc3161TimestampToken.TryDecode(resp.TimeStampToken.GetValueOrDefault(), out token, out _))
            {
                if (shouldThrow)
                {
                    throw new CryptographicException(SR.Cryptography_TimestampReq_BadResponse);
                }

                bytesConsumed = 0;
                status        = Rfc3161RequestResponseStatus.DoesNotParse;
                return(false);
            }

            status = ValidateResponse(token, shouldThrow);
            return(status == Rfc3161RequestResponseStatus.Accepted);
        }
Esempio n. 10
0
        /// <summary>
        ///   Decodes the specified Certificate Revocation List (CRL) and produces
        ///   a <see cref="CertificateRevocationListBuilder" /> with all of the revocation
        ///   entries from the decoded CRL.
        /// </summary>
        /// <param name="currentCrl">
        ///   The DER-encoded CRL to decode.
        /// </param>
        /// <param name="currentCrlNumber">
        ///   When this method returns, contains the CRL sequence number from the decoded CRL.
        ///   This parameter is treated as uninitialized.
        /// </param>
        /// <param name="bytesConsumed">
        ///   When this method returns, contains the number of bytes that were read from
        ///   <paramref name="currentCrl"/> while decoding.
        /// </param>
        /// <returns>
        ///   A new builder that has the same revocation entries as the decoded CRL.
        /// </returns>
        /// <exception cref="CryptographicException">
        ///   <paramref name="currentCrl" /> could not be decoded.
        /// </exception>
        public static CertificateRevocationListBuilder Load(
            ReadOnlySpan <byte> currentCrl,
            out BigInteger currentCrlNumber,
            out int bytesConsumed)
        {
            List <RevokedCertificate> list = new();
            BigInteger crlNumber           = 0;
            int        payloadLength;

            try
            {
                AsnValueReader reader = new AsnValueReader(currentCrl, AsnEncodingRules.DER);
                payloadLength = reader.PeekEncodedValue().Length;

                AsnValueReader certificateList = reader.ReadSequence();
                AsnValueReader tbsCertList     = certificateList.ReadSequence();
                AlgorithmIdentifierAsn.Decode(ref certificateList, ReadOnlyMemory <byte> .Empty, out _);

                if (!certificateList.TryReadPrimitiveBitString(out _, out _))
                {
                    throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
                }

                certificateList.ThrowIfNotEmpty();

                int version = 0;

                if (tbsCertList.PeekTag().HasSameClassAndValue(Asn1Tag.Integer))
                {
                    // https://datatracker.ietf.org/doc/html/rfc5280#section-5.1 says the only
                    // version values are v1 (0) and v2 (1).
                    //
                    // Since v1 (0) is supposed to not write down the version value, v2 (1) is the
                    // only legal value to read.
                    if (!tbsCertList.TryReadInt32(out version) || version != 1)
                    {
                        throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
                    }
                }

                AlgorithmIdentifierAsn.Decode(ref tbsCertList, ReadOnlyMemory <byte> .Empty, out _);
                // X500DN
                tbsCertList.ReadSequence();

                // thisUpdate
                ReadX509Time(ref tbsCertList);

                // nextUpdate
                ReadX509TimeOpt(ref tbsCertList);

                AsnValueReader revokedCertificates = default;

                if (tbsCertList.HasData && tbsCertList.PeekTag().HasSameClassAndValue(Asn1Tag.Sequence))
                {
                    revokedCertificates = tbsCertList.ReadSequence();
                }

                if (version > 0 && tbsCertList.HasData)
                {
                    AsnValueReader crlExtensionsExplicit = tbsCertList.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
                    AsnValueReader crlExtensions         = crlExtensionsExplicit.ReadSequence();
                    crlExtensionsExplicit.ThrowIfNotEmpty();

                    while (crlExtensions.HasData)
                    {
                        AsnValueReader extension = crlExtensions.ReadSequence();
                        Oid?           extnOid   = Oids.GetSharedOrNullOid(ref extension);

                        if (extnOid is null)
                        {
                            extension.ReadObjectIdentifier();
                        }

                        if (extension.PeekTag().HasSameClassAndValue(Asn1Tag.Boolean))
                        {
                            extension.ReadBoolean();
                        }

                        if (!extension.TryReadPrimitiveOctetString(out ReadOnlySpan <byte> extnValue))
                        {
                            throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
                        }

                        // Since we're only matching against OIDs that come from GetSharedOrNullOid
                        // we can use ReferenceEquals and skip the Value string equality check in
                        // the Oid.ValueEquals extension method (as it will always be preempted by
                        // the ReferenceEquals or will evaulate to false).
                        if (ReferenceEquals(extnOid, Oids.CrlNumberOid))
                        {
                            AsnValueReader crlNumberReader = new AsnValueReader(
                                extnValue,
                                AsnEncodingRules.DER);

                            crlNumber = crlNumberReader.ReadInteger();
                            crlNumberReader.ThrowIfNotEmpty();
                        }
                    }
                }

                tbsCertList.ThrowIfNotEmpty();

                while (revokedCertificates.HasData)
                {
                    RevokedCertificate revokedCertificate = new RevokedCertificate(ref revokedCertificates, version);
                    list.Add(revokedCertificate);
                }
            }
            catch (AsnContentException e)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e);
            }

            bytesConsumed    = payloadLength;
            currentCrlNumber = crlNumber;
            return(new CertificateRevocationListBuilder(list));
        }
        private void Decode(ReadOnlySpan <byte> rawData)
        {
            _keyIdentifier = null;
            _simpleIssuer  = null;
            _rawIssuer     = null;
            _serialNumber  = null;

            // https://datatracker.ietf.org/doc/html/rfc3280#section-4.2.1.1
            // AuthorityKeyIdentifier ::= SEQUENCE {
            //    keyIdentifier[0] KeyIdentifier OPTIONAL,
            //    authorityCertIssuer[1] GeneralNames OPTIONAL,
            //    authorityCertSerialNumber[2] CertificateSerialNumber OPTIONAL  }
            //
            // KeyIdentifier::= OCTET STRING

            try
            {
                AsnValueReader reader = new AsnValueReader(rawData, AsnEncodingRules.DER);
                AsnValueReader aki    = reader.ReadSequence();
                reader.ThrowIfNotEmpty();

                Asn1Tag nextTag = default;

                if (aki.HasData)
                {
                    nextTag = aki.PeekTag();
                }

                if (nextTag.HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
                {
                    _keyIdentifier = aki.ReadOctetString(nextTag);

                    if (aki.HasData)
                    {
                        nextTag = aki.PeekTag();
                    }
                }

                if (nextTag.HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 1)))
                {
                    byte[] rawIssuer = aki.PeekEncodedValue().ToArray();
                    _rawIssuer = rawIssuer;

                    AsnValueReader generalNames = aki.ReadSequence(nextTag);
                    bool           foundIssuer  = false;

                    // Walk all of the entities to make sure they decode legally, so no early abort.
                    while (generalNames.HasData)
                    {
                        GeneralNameAsn.Decode(ref generalNames, rawIssuer, out GeneralNameAsn decoded);

                        if (decoded.DirectoryName.HasValue)
                        {
                            if (!foundIssuer)
                            {
                                // Only ever try reading the first one.
                                // Don't just use a null check or we would load the last of an odd number.
                                foundIssuer = true;

                                _simpleIssuer = new X500DistinguishedName(
                                    decoded.DirectoryName.GetValueOrDefault().Span);
                            }
                            else
                            {
                                _simpleIssuer = null;
                            }
                        }
                    }

                    if (aki.HasData)
                    {
                        nextTag = aki.PeekTag();
                    }
                }

                if (nextTag.HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 2)))
                {
                    _serialNumber = aki.ReadIntegerBytes(nextTag).ToArray();
                }

                aki.ThrowIfNotEmpty();
            }
            catch (AsnContentException e)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e);
            }

            _decoded = true;
        }
Esempio n. 12
0
        private static unsafe CertificateRequest LoadSigningRequest(
            ReadOnlySpan <byte> pkcs10,
            bool permitTrailingData,
            HashAlgorithmName signerHashAlgorithm,
            out int bytesConsumed,
            CertificateRequestLoadOptions options,
            RSASignaturePadding?signerSignaturePadding)
        {
            ArgumentException.ThrowIfNullOrEmpty(signerHashAlgorithm.Name, nameof(signerHashAlgorithm));

            if ((options & ~AllOptions) != 0)
            {
                throw new ArgumentOutOfRangeException(nameof(options), options, SR.Argument_InvalidFlag);
            }

            bool skipSignatureValidation =
                (options & CertificateRequestLoadOptions.SkipSignatureValidation) != 0;

            bool unsafeLoadCertificateExtensions =
                (options & CertificateRequestLoadOptions.UnsafeLoadCertificateExtensions) != 0;

            try
            {
                AsnValueReader outer         = new AsnValueReader(pkcs10, AsnEncodingRules.DER);
                int            encodedLength = outer.PeekEncodedValue().Length;

                AsnValueReader     pkcs10Asn = outer.ReadSequence();
                CertificateRequest req;

                if (!permitTrailingData)
                {
                    outer.ThrowIfNotEmpty();
                }

                fixed(byte *p10ptr = pkcs10)
                {
                    using (PointerMemoryManager <byte> manager = new PointerMemoryManager <byte>(p10ptr, encodedLength))
                    {
                        ReadOnlyMemory <byte>       rebind             = manager.Memory;
                        ReadOnlySpan <byte>         encodedRequestInfo = pkcs10Asn.PeekEncodedValue();
                        CertificationRequestInfoAsn requestInfo;
                        AlgorithmIdentifierAsn      algorithmIdentifier;
                        ReadOnlySpan <byte>         signature;
                        int signatureUnusedBitCount;

                        CertificationRequestInfoAsn.Decode(ref pkcs10Asn, rebind, out requestInfo);
                        AlgorithmIdentifierAsn.Decode(ref pkcs10Asn, rebind, out algorithmIdentifier);

                        if (!pkcs10Asn.TryReadPrimitiveBitString(out signatureUnusedBitCount, out signature))
                        {
                            throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
                        }

                        pkcs10Asn.ThrowIfNotEmpty();

                        if (requestInfo.Version < 0)
                        {
                            throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
                        }

                        // They haven't bumped from v0 to v1 as of 2022.
                        const int MaxSupportedVersion = 0;

                        if (requestInfo.Version != MaxSupportedVersion)
                        {
                            throw new CryptographicException(
                                      SR.Format(
                                          SR.Cryptography_CertReq_Load_VersionTooNew,
                                          requestInfo.Version,
                                          MaxSupportedVersion));
                        }

                        PublicKey publicKey = PublicKey.DecodeSubjectPublicKeyInfo(ref requestInfo.SubjectPublicKeyInfo);

                        if (!skipSignatureValidation)
                        {
                            // None of the supported signature algorithms support signatures that are not full bytes.
                            // So, shortcut the verification on the bit length
                            if (signatureUnusedBitCount != 0 ||
                                !VerifyX509Signature(encodedRequestInfo, signature, publicKey, algorithmIdentifier))
                            {
                                throw new CryptographicException(SR.Cryptography_CertReq_SignatureVerificationFailed);
                            }
                        }

                        X500DistinguishedName subject = new X500DistinguishedName(requestInfo.Subject.Span);

                        req = new CertificateRequest(
                            subject,
                            publicKey,
                            signerHashAlgorithm,
                            signerSignaturePadding);

                        if (requestInfo.Attributes is not null)
                        {
                            bool foundCertExt = false;

                            foreach (AttributeAsn attr in requestInfo.Attributes)
                            {
                                if (attr.AttrType == Oids.Pkcs9ExtensionRequest)
                                {
                                    if (foundCertExt)
                                    {
                                        throw new CryptographicException(
                                                  SR.Cryptography_CertReq_Load_DuplicateExtensionRequests);
                                    }

                                    foundCertExt = true;

                                    if (attr.AttrValues.Length != 1)
                                    {
                                        throw new CryptographicException(
                                                  SR.Cryptography_CertReq_Load_DuplicateExtensionRequests);
                                    }

                                    AsnValueReader extsReader = new AsnValueReader(
                                        attr.AttrValues[0].Span,
                                        AsnEncodingRules.DER);

                                    AsnValueReader exts = extsReader.ReadSequence();
                                    extsReader.ThrowIfNotEmpty();

                                    // Minimum length is 1, so do..while
                                    do
                                    {
                                        X509ExtensionAsn.Decode(ref exts, rebind, out X509ExtensionAsn extAsn);

                                        if (unsafeLoadCertificateExtensions)
                                        {
                                            X509Extension ext = new X509Extension(
                                                extAsn.ExtnId,
                                                extAsn.ExtnValue.Span,
                                                extAsn.Critical);

                                            X509Extension?rich =
                                                X509Certificate2.CreateCustomExtensionIfAny(extAsn.ExtnId);

                                            if (rich is not null)
                                            {
                                                rich.CopyFrom(ext);
                                                req.CertificateExtensions.Add(rich);
                                            }
                                            else
                                            {
                                                req.CertificateExtensions.Add(ext);
                                            }
                                        }
                                    } while (exts.HasData);
                                }
                                else
                                {
                                    if (attr.AttrValues.Length == 0)
                                    {
                                        throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
                                    }

                                    foreach (ReadOnlyMemory <byte> val in attr.AttrValues)
                                    {
                                        req.OtherRequestAttributes.Add(
                                            new AsnEncodedData(attr.AttrType, val.Span));
                                    }
                                }
                            }
                        }
                    }
                }

                bytesConsumed = encodedLength;
                return(req);
            }
            catch (AsnContentException e)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e);
            }
        }