Exemplo n.º 1
0
 internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory <byte> rebind, out TbsCertificateAsn decoded)
 {
     Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
 }
Exemplo n.º 2
0
        public override DecryptorPal Decode(
            byte[] encodedMessage,
            out int version,
            out ContentInfo contentInfo,
            out AlgorithmIdentifier contentEncryptionAlgorithm,
            out X509Certificate2Collection originatorCerts,
            out CryptographicAttributeObjectCollection unprotectedAttributes)
        {
            // Read using BER because the CMS specification says the encoding is BER.
            AsnValueReader reader = new AsnValueReader(encodedMessage, AsnEncodingRules.BER);

            ContentInfoAsn.Decode(
                ref reader,
                encodedMessage,
                out ContentInfoAsn parsedContentInfo);

            if (parsedContentInfo.ContentType != Oids.Pkcs7Enveloped)
            {
                throw new CryptographicException(SR.Cryptography_Cms_InvalidMessageType);
            }

            byte[] copy = parsedContentInfo.Content.ToArray();

            EnvelopedDataAsn data = EnvelopedDataAsn.Decode(copy, AsnEncodingRules.BER);

            version = data.Version;

            contentInfo = new ContentInfo(
                new Oid(data.EncryptedContentInfo.ContentType),
                data.EncryptedContentInfo.EncryptedContent?.ToArray() ?? Array.Empty <byte>());

            contentEncryptionAlgorithm =
                data.EncryptedContentInfo.ContentEncryptionAlgorithm.ToPresentationObject();

            originatorCerts = new X509Certificate2Collection();

            if (data.OriginatorInfo.HasValue && data.OriginatorInfo.Value.CertificateSet != null)
            {
                foreach (CertificateChoiceAsn certChoice in data.OriginatorInfo.Value.CertificateSet)
                {
                    if (certChoice.Certificate != null)
                    {
                        originatorCerts.Add(new X509Certificate2(certChoice.Certificate.Value.ToArray()));
                    }
                }
            }

            unprotectedAttributes = SignerInfo.MakeAttributeCollection(data.UnprotectedAttributes);

            var recipientInfos = new List <RecipientInfo>();

            foreach (RecipientInfoAsn recipientInfo in data.RecipientInfos)
            {
                if (recipientInfo.Ktri.HasValue)
                {
                    recipientInfos.Add(new KeyTransRecipientInfo(new ManagedKeyTransPal(recipientInfo.Ktri.Value)));
                }
                else if (recipientInfo.Kari.HasValue)
                {
                    for (int i = 0; i < recipientInfo.Kari.Value.RecipientEncryptedKeys.Length; i++)
                    {
                        recipientInfos.Add(
                            new KeyAgreeRecipientInfo(new ManagedKeyAgreePal(recipientInfo.Kari.Value, i)));
                    }
                }
                else
                {
                    Debug.Fail($"{nameof(RecipientInfoAsn)} deserialized with an unknown recipient type");
                    throw new CryptographicException();
                }
            }

            return(new ManagedDecryptorPal(copy, data, new RecipientInfoCollection(recipientInfos)));
        }
Exemplo n.º 3
0
 internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory <byte> rebind, out KeyTransRecipientInfoAsn decoded)
 {
     Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
 }
 internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory <byte> rebind, out RecipientEncryptedKeyAsn decoded)
 {
     Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
 }
Exemplo n.º 5
0
 internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory <byte> rebind, out SignedDataAsn decoded)
 {
     Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
 }
 internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory <byte> rebind, out OtherKeyAttributeAsn decoded)
 {
     Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
 }
Exemplo n.º 7
0
        private static void DecodeCore(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory <byte> rebind, out Rfc3161TimeStampReq decoded)
        {
            decoded = default;
            AsnValueReader      sequenceReader = reader.ReadSequence(expectedTag);
            AsnValueReader      defaultReader;
            AsnValueReader      collectionReader;
            ReadOnlySpan <byte> rebindSpan = rebind.Span;
            int offset;
            ReadOnlySpan <byte> tmpSpan;


            if (!sequenceReader.TryReadInt32(out decoded.Version))
            {
                sequenceReader.ThrowIfNotEmpty();
            }

            System.Security.Cryptography.Pkcs.Asn1.MessageImprint.Decode(ref sequenceReader, rebind, out decoded.MessageImprint);

            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.ObjectIdentifier))
            {
                decoded.ReqPolicy = sequenceReader.ReadObjectIdentifier();
            }


            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Integer))
            {
                tmpSpan       = sequenceReader.ReadIntegerBytes();
                decoded.Nonce = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
            }


            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Boolean))
            {
                decoded.CertReq = sequenceReader.ReadBoolean();
            }
            else
            {
                defaultReader   = new AsnValueReader(DefaultCertReq, AsnEncodingRules.DER);
                decoded.CertReq = defaultReader.ReadBoolean();
            }


            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
            {
                // Decode SEQUENCE OF for Extensions
                {
                    collectionReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
                    var tmpList = new List <System.Security.Cryptography.Asn1.X509ExtensionAsn>();
                    System.Security.Cryptography.Asn1.X509ExtensionAsn tmpItem;

                    while (collectionReader.HasData)
                    {
                        System.Security.Cryptography.Asn1.X509ExtensionAsn.Decode(ref collectionReader, rebind, out tmpItem);
                        tmpList.Add(tmpItem);
                    }

                    decoded.Extensions = tmpList.ToArray();
                }
            }


            sequenceReader.ThrowIfNotEmpty();
        }
        private static string?FindAltNameMatch(byte[] extensionBytes, GeneralNameType matchType, string?otherOid)
        {
            // If Other, have OID, else, no OID.
            Debug.Assert(
                (otherOid == null) == (matchType != GeneralNameType.OtherName),
                $"otherOid has incorrect nullarity for matchType {matchType}");

            Debug.Assert(
                matchType == GeneralNameType.UniformResourceIdentifier ||
                matchType == GeneralNameType.DnsName ||
                matchType == GeneralNameType.Email ||
                matchType == GeneralNameType.OtherName,
                $"matchType ({matchType}) is not currently supported");

            Debug.Assert(
                otherOid == null || otherOid == Oids.UserPrincipalName,
                $"otherOid ({otherOid}) is not supported");

            try
            {
                AsnValueReader reader         = new AsnValueReader(extensionBytes, AsnEncodingRules.DER);
                AsnValueReader sequenceReader = reader.ReadSequence();
                reader.ThrowIfNotEmpty();

                while (sequenceReader.HasData)
                {
                    GeneralNameAsn.Decode(ref sequenceReader, extensionBytes, out GeneralNameAsn generalName);

                    switch (matchType)
                    {
                    case GeneralNameType.OtherName:
                        // If the OtherName OID didn't match, move to the next entry.
                        if (generalName.OtherName.HasValue && generalName.OtherName.Value.TypeId == otherOid)
                        {
                            // Currently only UPN is supported, which is a UTF8 string per
                            // https://msdn.microsoft.com/en-us/library/ff842518.aspx
                            AsnValueReader nameReader = new AsnValueReader(
                                generalName.OtherName.Value.Value.Span,
                                AsnEncodingRules.DER);

                            string udnName = nameReader.ReadCharacterString(UniversalTagNumber.UTF8String);
                            nameReader.ThrowIfNotEmpty();
                            return(udnName);
                        }

                        break;

                    case GeneralNameType.Rfc822Name:
                        if (generalName.Rfc822Name != null)
                        {
                            return(generalName.Rfc822Name);
                        }

                        break;

                    case GeneralNameType.DnsName:
                        if (generalName.DnsName != null)
                        {
                            return(generalName.DnsName);
                        }

                        break;

                    case GeneralNameType.UniformResourceIdentifier:
                        if (generalName.Uri != null)
                        {
                            return(generalName.Uri);
                        }

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

            return(null);
        }
Exemplo n.º 9
0
 internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory <byte> rebind, out DistributionPointAsn decoded)
 {
     Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
 }
        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;
        }
Exemplo n.º 11
0
 internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory <byte> rebind, out OriginatorPublicKeyAsn decoded)
 {
     Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
 }
Exemplo n.º 12
0
 internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory <byte> rebind, out MessageImprint decoded)
 {
     Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
 }
Exemplo n.º 13
0
 public static void Decode(ref AsnValueReader reader, ReadOnlyMemory <byte> rebind, out EnvelopedDataAsn decoded)
 {
     Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
 }
Exemplo n.º 14
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);
        }
Exemplo n.º 15
0
        private static string?GetCdpUrl(SafeX509Handle cert)
        {
            ArraySegment <byte> crlDistributionPoints =
                OpenSslX509CertificateReader.FindFirstExtension(cert, Oids.CrlDistributionPoints);

            if (crlDistributionPoints.Array == null)
            {
                if (OpenSslX509ChainEventSource.Log.IsEnabled())
                {
                    OpenSslX509ChainEventSource.Log.NoCdpFound(cert);
                }

                return(null);
            }

            try
            {
                AsnValueReader reader         = new AsnValueReader(crlDistributionPoints, AsnEncodingRules.DER);
                AsnValueReader sequenceReader = reader.ReadSequence();
                reader.ThrowIfNotEmpty();

                while (sequenceReader.HasData)
                {
                    DistributionPointAsn.Decode(ref sequenceReader, crlDistributionPoints, out DistributionPointAsn distributionPoint);

                    // Only distributionPoint is supported
                    // Only fullName is supported, nameRelativeToCRLIssuer is for LDAP-based lookup.
                    if (distributionPoint.DistributionPoint.HasValue &&
                        distributionPoint.DistributionPoint.Value.FullName != null)
                    {
                        foreach (GeneralNameAsn name in distributionPoint.DistributionPoint.Value.FullName)
                        {
                            if (name.Uri != null)
                            {
                                if (Uri.TryCreate(name.Uri, UriKind.Absolute, out Uri? uri) &&
                                    uri.Scheme == "http")
                                {
                                    return(name.Uri);
                                }
                                else
                                {
                                    if (OpenSslX509ChainEventSource.Log.IsEnabled())
                                    {
                                        OpenSslX509ChainEventSource.Log.NonHttpCdpEntry(name.Uri);
                                    }
                                }
                            }
                        }

                        if (OpenSslX509ChainEventSource.Log.IsEnabled())
                        {
                            OpenSslX509ChainEventSource.Log.NoMatchingCdpEntry();
                        }
                    }
                }
            }
            catch (CryptographicException)
            {
                // Treat any ASN errors as if the extension was missing.
            }
            catch (AsnContentException)
            {
                // Treat any ASN errors as if the extension was missing.
            }
            finally
            {
                // The data came from a certificate, so it's public.
                CryptoPool.Return(crlDistributionPoints.Array, clearSize: 0);
            }

            return(null);
        }
Exemplo n.º 16
0
        public static Pkcs12Info Decode(
            ReadOnlyMemory <byte> encodedBytes,
            out int bytesConsumed,
            bool skipCopy = false)
        {
            AsnReader reader = new AsnReader(encodedBytes, AsnEncodingRules.BER);

            // Trim it to the first value
            encodedBytes = reader.PeekEncodedValue();

            ReadOnlyMemory <byte> maybeCopy = skipCopy ? encodedBytes : encodedBytes.ToArray();
            PfxAsn pfx = PfxAsn.Decode(maybeCopy, AsnEncodingRules.BER);

            // https://tools.ietf.org/html/rfc7292#section-4 only defines version 3.
            if (pfx.Version != 3)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
            }

            ReadOnlyMemory <byte> authSafeBytes = ReadOnlyMemory <byte> .Empty;
            Pkcs12IntegrityMode   mode          = Pkcs12IntegrityMode.Unknown;

            if (pfx.AuthSafe.ContentType == Oids.Pkcs7Data)
            {
                authSafeBytes = PkcsHelpers.DecodeOctetStringAsMemory(pfx.AuthSafe.Content);

                if (pfx.MacData.HasValue)
                {
                    mode = Pkcs12IntegrityMode.Password;
                }
                else
                {
                    mode = Pkcs12IntegrityMode.None;
                }
            }
            else if (pfx.AuthSafe.ContentType == Oids.Pkcs7Signed)
            {
                SignedDataAsn signedData = SignedDataAsn.Decode(pfx.AuthSafe.Content, AsnEncodingRules.BER);

                mode = Pkcs12IntegrityMode.PublicKey;

                if (signedData.EncapContentInfo.ContentType == Oids.Pkcs7Data)
                {
                    authSafeBytes = signedData.EncapContentInfo.Content.GetValueOrDefault();
                }

                if (pfx.MacData.HasValue)
                {
                    throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
                }
            }

            if (mode == Pkcs12IntegrityMode.Unknown)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
            }

            List <ContentInfoAsn> authSafeData   = new List <ContentInfoAsn>();
            AsnValueReader        authSafeReader = new AsnValueReader(authSafeBytes.Span, AsnEncodingRules.BER);
            AsnValueReader        sequenceReader = authSafeReader.ReadSequence();

            authSafeReader.ThrowIfNotEmpty();
            while (sequenceReader.HasData)
            {
                ContentInfoAsn.Decode(ref sequenceReader, authSafeBytes, out ContentInfoAsn contentInfo);
                authSafeData.Add(contentInfo);
            }

            ReadOnlyCollection <Pkcs12SafeContents> authSafe;

            if (authSafeData.Count == 0)
            {
                authSafe = new ReadOnlyCollection <Pkcs12SafeContents>(Array.Empty <Pkcs12SafeContents>());
            }
            else
            {
                Pkcs12SafeContents[] contentsArray = new Pkcs12SafeContents[authSafeData.Count];

                for (int i = 0; i < contentsArray.Length; i++)
                {
                    contentsArray[i] = new Pkcs12SafeContents(authSafeData[i]);
                }

                authSafe = new ReadOnlyCollection <Pkcs12SafeContents>(contentsArray);
            }

            bytesConsumed = encodedBytes.Length;

            return(new Pkcs12Info
            {
                AuthenticatedSafe = authSafe,
                IntegrityMode = mode,
                _decoded = pfx,
                _authSafeContents = authSafeBytes,
            });
        }
 internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory <byte> rebind, out BasicConstraintsAsn decoded)
 {
     Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
 }
 internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory <byte> rebind, out PolicyInformation decoded)
 {
     Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
 }
Exemplo n.º 19
0
        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory <byte> rebind, out Rfc3161TstInfo decoded)
        {
            decoded = default;
            AsnValueReader      sequenceReader = reader.ReadSequence(expectedTag);
            AsnValueReader      explicitReader;
            AsnValueReader      defaultReader;
            AsnValueReader      collectionReader;
            ReadOnlySpan <byte> rebindSpan = rebind.Span;
            int offset;
            ReadOnlySpan <byte> tmpSpan;


            if (!sequenceReader.TryReadInt32(out decoded.Version))
            {
                sequenceReader.ThrowIfNotEmpty();
            }

            decoded.Policy = sequenceReader.ReadObjectIdentifier();
            System.Security.Cryptography.Pkcs.Asn1.MessageImprint.Decode(ref sequenceReader, rebind, out decoded.MessageImprint);
            tmpSpan = sequenceReader.ReadIntegerBytes();
            decoded.SerialNumber = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
            decoded.GenTime      = sequenceReader.ReadGeneralizedTime();

            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Sequence))
            {
                System.Security.Cryptography.Pkcs.Asn1.Rfc3161Accuracy tmpAccuracy;
                System.Security.Cryptography.Pkcs.Asn1.Rfc3161Accuracy.Decode(ref sequenceReader, rebind, out tmpAccuracy);
                decoded.Accuracy = tmpAccuracy;
            }


            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Boolean))
            {
                decoded.Ordering = sequenceReader.ReadBoolean();
            }
            else
            {
                defaultReader    = new AsnValueReader(DefaultOrdering, AsnEncodingRules.DER);
                decoded.Ordering = defaultReader.ReadBoolean();
            }


            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Integer))
            {
                tmpSpan       = sequenceReader.ReadIntegerBytes();
                decoded.Nonce = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
            }


            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
            {
                explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
                System.Security.Cryptography.Asn1.GeneralNameAsn tmpTsa;
                System.Security.Cryptography.Asn1.GeneralNameAsn.Decode(ref explicitReader, rebind, out tmpTsa);
                decoded.Tsa = tmpTsa;

                explicitReader.ThrowIfNotEmpty();
            }


            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 1)))
            {
                // Decode SEQUENCE OF for Extensions
                {
                    collectionReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 1));
                    var tmpList = new List <System.Security.Cryptography.Asn1.X509ExtensionAsn>();
                    System.Security.Cryptography.Asn1.X509ExtensionAsn tmpItem;

                    while (collectionReader.HasData)
                    {
                        System.Security.Cryptography.Asn1.X509ExtensionAsn.Decode(ref collectionReader, rebind, out tmpItem);
                        tmpList.Add(tmpItem);
                    }

                    decoded.Extensions = tmpList.ToArray();
                }
            }


            sequenceReader.ThrowIfNotEmpty();
        }
Exemplo n.º 20
0
        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory <byte> rebind, out SignedDataAsn decoded)
        {
            decoded = default;
            AsnValueReader      sequenceReader = reader.ReadSequence(expectedTag);
            AsnValueReader      collectionReader;
            ReadOnlySpan <byte> rebindSpan = rebind.Span;
            int offset;
            ReadOnlySpan <byte> tmpSpan;


            if (!sequenceReader.TryReadInt32(out decoded.Version))
            {
                sequenceReader.ThrowIfNotEmpty();
            }


            // Decode SEQUENCE OF for DigestAlgorithms
            {
                collectionReader = sequenceReader.ReadSetOf();
                var tmpList = new List <System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn>();
                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn tmpItem;

                while (collectionReader.HasData)
                {
                    System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref collectionReader, rebind, out tmpItem);
                    tmpList.Add(tmpItem);
                }

                decoded.DigestAlgorithms = tmpList.ToArray();
            }

            System.Security.Cryptography.Pkcs.Asn1.EncapsulatedContentInfoAsn.Decode(ref sequenceReader, rebind, out decoded.EncapContentInfo);

            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
            {
                // Decode SEQUENCE OF for CertificateSet
                {
                    collectionReader = sequenceReader.ReadSetOf(new Asn1Tag(TagClass.ContextSpecific, 0));
                    var tmpList = new List <System.Security.Cryptography.Pkcs.Asn1.CertificateChoiceAsn>();
                    System.Security.Cryptography.Pkcs.Asn1.CertificateChoiceAsn tmpItem;

                    while (collectionReader.HasData)
                    {
                        System.Security.Cryptography.Pkcs.Asn1.CertificateChoiceAsn.Decode(ref collectionReader, rebind, out tmpItem);
                        tmpList.Add(tmpItem);
                    }

                    decoded.CertificateSet = tmpList.ToArray();
                }
            }


            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 1)))
            {
                // Decode SEQUENCE OF for Crls
                {
                    collectionReader = sequenceReader.ReadSetOf(new Asn1Tag(TagClass.ContextSpecific, 1));
                    var tmpList = new List <ReadOnlyMemory <byte> >();
                    ReadOnlyMemory <byte> tmpItem;

                    while (collectionReader.HasData)
                    {
                        tmpSpan = collectionReader.ReadEncodedValue();
                        tmpItem = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
                        tmpList.Add(tmpItem);
                    }

                    decoded.Crls = tmpList.ToArray();
                }
            }


            // Decode SEQUENCE OF for SignerInfos
            {
                collectionReader = sequenceReader.ReadSetOf();
                var tmpList = new List <System.Security.Cryptography.Pkcs.Asn1.SignerInfoAsn>();
                System.Security.Cryptography.Pkcs.Asn1.SignerInfoAsn tmpItem;

                while (collectionReader.HasData)
                {
                    System.Security.Cryptography.Pkcs.Asn1.SignerInfoAsn.Decode(ref collectionReader, rebind, out tmpItem);
                    tmpList.Add(tmpItem);
                }

                decoded.SignerInfos = tmpList.ToArray();
            }


            sequenceReader.ThrowIfNotEmpty();
        }
        private string?FormatSubjectAlternativeName(byte[] rawData)
        {
            // Because SubjectAlternativeName is a commonly parsed structure, we'll
            // specifically format this one.  And we'll match the OpenSSL format, which
            // includes not localizing any of the values (or respecting the multiLine boolean)
            //
            // The intent here is to be functionally equivalent to OpenSSL GENERAL_NAME_print.

            try
            {
                StringBuilder  output           = new StringBuilder();
                AsnValueReader reader           = new AsnValueReader(rawData, AsnEncodingRules.DER);
                AsnValueReader collectionReader = reader.ReadSequence();

                reader.ThrowIfNotEmpty();

                while (collectionReader.HasData)
                {
                    GeneralNameAsn.Decode(ref collectionReader, rawData, out GeneralNameAsn generalName);

                    if (output.Length != 0)
                    {
                        output.Append(", ");
                    }

                    if (generalName.OtherName.HasValue)
                    {
                        output.Append("othername:<unsupported>");
                    }
                    else if (generalName.Rfc822Name != null)
                    {
                        output.Append("email:");
                        output.Append(generalName.Rfc822Name);
                    }
                    else if (generalName.DnsName != null)
                    {
                        output.Append("DNS:");
                        output.Append(generalName.DnsName);
                    }
                    else if (generalName.X400Address != null)
                    {
                        output.Append("X400Name:<unsupported>");
                    }
                    else if (generalName.DirectoryName != null)
                    {
                        // OpenSSL supports printing one of these, but the logic lives in X509Certificates,
                        // and it isn't very common.  So we'll skip this one until someone asks for it.
                        output.Append("DirName:<unsupported>");
                    }
                    else if (generalName.EdiPartyName != null)
                    {
                        output.Append("EdiPartyName:<unsupported>");
                    }
                    else if (generalName.Uri != null)
                    {
                        output.Append("URI:");
                        output.Append(generalName.Uri);
                    }
                    else if (generalName.IPAddress.HasValue)
                    {
                        ReadOnlySpan <byte> ipAddressBytes = generalName.IPAddress.Value.Span;

                        output.Append("IP Address");
                        if (ipAddressBytes.Length == 4)
                        {
                            // Add the colon and dotted-decimal representation of IPv4.
                            output.Append(
                                $":{ipAddressBytes[0]}.{ipAddressBytes[1]}.{ipAddressBytes[2]}.{ipAddressBytes[3]}");
                        }
                        else if (ipAddressBytes.Length == 16)
                        {
                            // Print the IP Address value as colon separated UInt16 hex values without leading zeroes.
                            // 20 01 0D B8 AC 10 FE 01 00 00 00 00 00 00 00 00
                            //
                            // IP Address:2001:DB8:AC10:FE01:0:0:0:0
                            for (int i = 0; i < ipAddressBytes.Length; i += 2)
                            {
                                output.Append($":{ipAddressBytes[i] << 8 | ipAddressBytes[i + 1]:X}");
                            }
                        }
                        else
                        {
                            output.Append(":<invalid>");
                        }
                    }
                    else if (generalName.RegisteredId != null)
                    {
                        output.Append("Registered ID:");
                        output.Append(generalName.RegisteredId);
                    }
                    else
                    {
                        // A new extension to GeneralName could legitimately hit this,
                        // but it's correct to say that until we know what that is that
                        // the pretty-print has failed, and we should fall back to hex.
                        //
                        // But it could also simply be poorly encoded user data.
                        return(null);
                    }
                }

                return(output.ToString());
            }
            catch (AsnContentException)
            {
                return(null);
            }
        }
Exemplo n.º 22
0
 internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory <byte> rebind, out EncapsulatedContentInfoAsn decoded)
 {
     Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
 }
Exemplo n.º 23
0
 internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory <byte> rebind, out AccessDescriptionAsn decoded)
 {
     Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
 }
Exemplo n.º 24
0
        private static List <Pkcs12SafeBag> ReadBags(ReadOnlyMemory <byte> serialized)
        {
            List <SafeBagAsn> serializedBags = new List <SafeBagAsn>();

            try
            {
                AsnValueReader reader         = new AsnValueReader(serialized.Span, AsnEncodingRules.BER);
                AsnValueReader sequenceReader = reader.ReadSequence();

                reader.ThrowIfNotEmpty();
                while (sequenceReader.HasData)
                {
                    SafeBagAsn.Decode(ref sequenceReader, serialized, out SafeBagAsn serializedBag);
                    serializedBags.Add(serializedBag);
                }

                if (serializedBags.Count == 0)
                {
                    return(new List <Pkcs12SafeBag>(0));
                }
            }
            catch (AsnContentException e)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e);
            }

            List <Pkcs12SafeBag> bags = new List <Pkcs12SafeBag>(serializedBags.Count);

            for (int i = 0; i < serializedBags.Count; i++)
            {
                ReadOnlyMemory <byte> bagValue = serializedBags[i].BagValue;
                Pkcs12SafeBag?        bag      = null;

                try
                {
                    switch (serializedBags[i].BagId)
                    {
                    case Oids.Pkcs12KeyBag:
                        bag = new Pkcs12KeyBag(bagValue);
                        break;

                    case Oids.Pkcs12ShroudedKeyBag:
                        bag = new Pkcs12ShroudedKeyBag(bagValue);
                        break;

                    case Oids.Pkcs12CertBag:
                        bag = Pkcs12CertBag.DecodeValue(bagValue);
                        break;

                    case Oids.Pkcs12CrlBag:
                        // Known, but no first-class support currently.
                        break;

                    case Oids.Pkcs12SecretBag:
                        bag = Pkcs12SecretBag.DecodeValue(bagValue);
                        break;

                    case Oids.Pkcs12SafeContentsBag:
                        bag = Pkcs12SafeContentsBag.Decode(bagValue);
                        break;
                    }
                }
                catch (AsnContentException)
                {
                }
                catch (CryptographicException)
                {
                }

                if (bag == null)
                {
                    bag = new Pkcs12SafeBag.UnknownBag(serializedBags[i].BagId, bagValue);
                }

                bag.Attributes = SignerInfo.MakeAttributeCollection(serializedBags[i].BagAttributes);
                bags.Add(bag);
            }

            return(bags);
        }
 internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory <byte> rebind, out IssuerAndSerialNumberAsn decoded)
 {
     Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
 }
 internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory <byte> rebind, out Rfc3161Accuracy decoded)
 {
     Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
 }
Exemplo n.º 27
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));
        }
Exemplo n.º 28
0
        private static void DecodeCore(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory <byte> rebind, out TbsCertificateAsn decoded)
        {
            decoded = default;
            AsnValueReader      sequenceReader = reader.ReadSequence(expectedTag);
            AsnValueReader      explicitReader;
            AsnValueReader      defaultReader;
            AsnValueReader      collectionReader;
            ReadOnlySpan <byte> rebindSpan = rebind.Span;
            int offset;
            ReadOnlySpan <byte> tmpSpan;


            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
            {
                explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));

                if (!explicitReader.TryReadInt32(out decoded.Version))
                {
                    explicitReader.ThrowIfNotEmpty();
                }

                explicitReader.ThrowIfNotEmpty();
            }
            else
            {
                defaultReader = new AsnValueReader(DefaultVersion, AsnEncodingRules.DER);

                if (!defaultReader.TryReadInt32(out decoded.Version))
                {
                    defaultReader.ThrowIfNotEmpty();
                }
            }

            tmpSpan = sequenceReader.ReadIntegerBytes();
            decoded.SerialNumber = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref sequenceReader, rebind, out decoded.SignatureAlgorithm);
            if (!sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag((UniversalTagNumber)16)))
            {
                throw new CryptographicException();
            }

            tmpSpan        = sequenceReader.ReadEncodedValue();
            decoded.Issuer = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
            System.Security.Cryptography.X509Certificates.Asn1.ValidityAsn.Decode(ref sequenceReader, rebind, out decoded.Validity);
            if (!sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag((UniversalTagNumber)16)))
            {
                throw new CryptographicException();
            }

            tmpSpan         = sequenceReader.ReadEncodedValue();
            decoded.Subject = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
            System.Security.Cryptography.Asn1.SubjectPublicKeyInfoAsn.Decode(ref sequenceReader, rebind, out decoded.SubjectPublicKeyInfo);

            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 1)))
            {
                if (sequenceReader.TryReadPrimitiveBitString(out _, out tmpSpan, new Asn1Tag(TagClass.ContextSpecific, 1)))
                {
                    decoded.IssuerUniqueId = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
                }
                else
                {
                    decoded.IssuerUniqueId = sequenceReader.ReadBitString(out _, new Asn1Tag(TagClass.ContextSpecific, 1));
                }
            }


            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 2)))
            {
                if (sequenceReader.TryReadPrimitiveBitString(out _, out tmpSpan, new Asn1Tag(TagClass.ContextSpecific, 2)))
                {
                    decoded.SubjectUniqueId = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
                }
                else
                {
                    decoded.SubjectUniqueId = sequenceReader.ReadBitString(out _, new Asn1Tag(TagClass.ContextSpecific, 2));
                }
            }


            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 3)))
            {
                explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 3));

                // Decode SEQUENCE OF for Extensions
                {
                    collectionReader = explicitReader.ReadSequence();
                    var tmpList = new List <System.Security.Cryptography.Asn1.X509ExtensionAsn>();
                    System.Security.Cryptography.Asn1.X509ExtensionAsn tmpItem;

                    while (collectionReader.HasData)
                    {
                        System.Security.Cryptography.Asn1.X509ExtensionAsn.Decode(ref collectionReader, rebind, out tmpItem);
                        tmpList.Add(tmpItem);
                    }

                    decoded.Extensions = tmpList.ToArray();
                }

                explicitReader.ThrowIfNotEmpty();
            }


            sequenceReader.ThrowIfNotEmpty();
        }
Exemplo n.º 29
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);
            }
        }