예제 #1
0
        public static void TagMustBeCorrect_Custom(PublicEncodingRules ruleSet)
        {
            byte[]    inputData = "87028837".HexToByteArray();
            AsnReader reader    = new AsnReader(inputData, (AsnEncodingRules)ruleSet);

            AssertExtensions.Throws <ArgumentException>(
                "expectedTag",
                () => reader.GetIntegerBytes(Asn1Tag.Null));

            Assert.True(reader.HasData, "HasData after bad universal tag");

            Assert.Throws <CryptographicException>(() => reader.ReadObjectIdentifierAsString());

            Assert.True(reader.HasData, "HasData after default tag");

            Assert.Throws <CryptographicException>(
                () => reader.ReadObjectIdentifierAsString(new Asn1Tag(TagClass.Application, 0)));

            Assert.True(reader.HasData, "HasData after wrong custom class");

            Assert.Throws <CryptographicException>(
                () => reader.ReadObjectIdentifierAsString(new Asn1Tag(TagClass.ContextSpecific, 1)));

            Assert.True(reader.HasData, "HasData after wrong custom tag value");

            Assert.Equal(
                "2.999",
                reader.ReadObjectIdentifierAsString(new Asn1Tag(TagClass.ContextSpecific, 7)));

            Assert.False(reader.HasData, "HasData after reading value");
        }
        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out CertificatePolicyMappingAsn decoded)
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            decoded = default;
            AsnReader sequenceReader = reader.ReadSequence(expectedTag);

            decoded.IssuerDomainPolicy  = sequenceReader.ReadObjectIdentifierAsString();
            decoded.SubjectDomainPolicy = sequenceReader.ReadObjectIdentifierAsString();

            sequenceReader.ThrowIfNotEmpty();
        }
예제 #3
0
        public static void ReadVeryLongOidArc(PublicEncodingRules ruleSet)
        {
            byte[] inputData = new byte[255];
            // 06 81 93 (OBJECT IDENTIFIER, 147 bytes).
            inputData[0] = 0x06;
            inputData[1] = 0x81;
            inputData[2] = 0x93;

            // With 147 bytes we get 147*7 = 1029 value bits.
            // The smallest legal number to encode would have a top byte of 0x81,
            // leaving 1022 bits remaining.  If they're all zero then we have 2^1022.
            //
            // Since it's our first sub-identifier it's really encoding "2.(2^1022 - 80)".
            inputData[3] = 0x81;
            // Leave the last byte as 0.
            new Span <byte>(inputData, 4, 145).Fill(0x80);

            const string ExpectedOid =
                "2." +
                "449423283715578976932326297697256183404494244735576643183575" +
                "202894331689513752407831771193306018840052800284699678483394" +
                "146974422036041556232118576598685310944419733562163713190755" +
                "549003115235298632707380212514422095376705856157203684782776" +
                "352068092908376276711465745599868114846199290762088390824060" +
                "56034224";

            AsnReader reader = new AsnReader(inputData, (AsnEncodingRules)ruleSet);

            string oidString = reader.ReadObjectIdentifierAsString();

            Assert.Equal(ExpectedOid, oidString);
        }
예제 #4
0
        private static IEnumerable <KeyValuePair <string, string> > ReadReverseRdns(X500DistinguishedName name)
        {
            AsnReader x500NameReader = new AsnReader(name.RawData, AsnEncodingRules.DER);
            AsnReader sequenceReader = x500NameReader.ReadSequence();
            var       rdnReaders     = new Stack <AsnReader>();

            x500NameReader.ThrowIfNotEmpty();

            while (sequenceReader.HasData)
            {
                rdnReaders.Push(sequenceReader.ReadSetOf());
            }

            while (rdnReaders.Count > 0)
            {
                AsnReader rdnReader = rdnReaders.Pop();
                while (rdnReader.HasData)
                {
                    AsnReader tavReader = rdnReader.ReadSequence();
                    string    oid       = tavReader.ReadObjectIdentifierAsString();
                    string    value     = tavReader.ReadAnyAsnString();
                    tavReader.ThrowIfNotEmpty();
                    yield return(new KeyValuePair <string, string>(oid, value));
                }
            }
        }
예제 #5
0
        public static void ReadVeryLongOid(PublicEncodingRules ruleSet)
        {
            byte[] inputData = new byte[100000];
            // 06 83 02 00 00 (OBJECT IDENTIFIER, 65536 bytes).
            inputData[0] = 0x06;
            inputData[1] = 0x83;
            inputData[2] = 0x01;
            inputData[3] = 0x00;
            inputData[4] = 0x00;
            // and the rest are all zero.

            // The first byte produces "0.0". Each of the remaining 65535 bytes produce
            // another ".0".
            const int     ExpectedLength = 65536 * 2 + 1;
            StringBuilder builder        = new StringBuilder(ExpectedLength);

            builder.Append('0');

            for (int i = 0; i <= ushort.MaxValue; i++)
            {
                builder.Append('.');
                builder.Append(0);
            }

            AsnReader reader    = new AsnReader(inputData, (AsnEncodingRules)ruleSet);
            string    oidString = reader.ReadObjectIdentifierAsString();

            Assert.Equal(ExpectedLength, oidString.Length);
            Assert.Equal(builder.ToString(), oidString);
        }
예제 #6
0
        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out PolicyInformation decoded)
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            decoded = default;
            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
            AsnReader collectionReader;

            decoded.PolicyIdentifier = sequenceReader.ReadObjectIdentifierAsString();

            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Sequence))
            {
                // Decode SEQUENCE OF for PolicyQualifiers
                {
                    collectionReader = sequenceReader.ReadSequence();
                    var tmpList = new List <System.Security.Cryptography.Pkcs.Asn1.PolicyQualifierInfo>();
                    System.Security.Cryptography.Pkcs.Asn1.PolicyQualifierInfo tmpItem;

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

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


            sequenceReader.ThrowIfNotEmpty();
        }
예제 #7
0
        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out CertificateTemplateAsn decoded)
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            decoded = default;
            AsnReader sequenceReader = reader.ReadSequence(expectedTag);

            decoded.TemplateID = sequenceReader.ReadObjectIdentifierAsString();

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


            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Integer))
            {
                if (sequenceReader.TryReadInt32(out int tmpTemplateMinorVersion))
                {
                    decoded.TemplateMinorVersion = tmpTemplateMinorVersion;
                }
                else
                {
                    sequenceReader.ThrowIfNotEmpty();
                }
            }


            sequenceReader.ThrowIfNotEmpty();
        }
예제 #8
0
        public static void ReadEcPublicKey()
        {
            const string PublicKeyValue =
                "04" +
                "2363DD131DA65E899A2E63E9E05E50C830D4994662FFE883DB2B9A767DCCABA2" +
                "F07081B5711BE1DEE90DFC8DE17970C2D937A16CD34581F52B8D59C9E9532D13";

            const string InputHex =
                "3059" +
                "3013" +
                "06072A8648CE3D0201" +
                "06082A8648CE3D030107" +
                "0342" +
                "00" +
                PublicKeyValue;

            byte[] inputData = InputHex.HexToByteArray();

            var spki = AsnSerializer.Deserialize <SubjectPublicKeyInfo>(
                inputData,
                AsnEncodingRules.DER);

            Assert.Equal("1.2.840.10045.2.1", spki.AlgorithmIdentifier.Algorithm.Value);
            Assert.Equal(PublicKeyValue, spki.PublicKey.ByteArrayToHex());

            AsnReader reader   = new AsnReader(spki.AlgorithmIdentifier.Parameters, AsnEncodingRules.DER);
            string    curveOid = reader.ReadObjectIdentifierAsString();

            Assert.False(reader.HasData, "reader.HasData");
            Assert.Equal("1.2.840.10045.3.1.7", curveOid);
        }
        public static IReadOnlyList <string> GetNameInfo(this X509Certificate2 certificate, string nameTypeOid, X509NameSource nameSource)
        {
            ThrowHelpers.CheckNullOrEempty(nameof(nameTypeOid), nameTypeOid);

            byte[] nameBytes = nameSource switch
            {
                X509NameSource.Issuer => certificate.IssuerName.RawData,
                X509NameSource.Subject => certificate.SubjectName.RawData,
                _ => ThrowHelpers.NotSupport <byte[], X509NameSource>(nameSource)
            };

            List <string> result = new List <string>();

            AsnReader nameReader   = new AsnReader(nameBytes, AsnEncodingRules.DER);
            AsnReader mainSequence = nameReader.ReadSequence();

            while (mainSequence.HasData)
            {
                AsnReader x509Name = mainSequence.ReadSetOf().ReadSequence();
                string    oid      = x509Name.ReadObjectIdentifierAsString();
                if (string.Equals(nameTypeOid, oid, StringComparison.Ordinal))
                {
                    result.Add(x509Name.GetCharacterString(UniversalTagNumber.PrintableString));
                }
            }

            return(result);
        }
    }
        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out EncryptedContentInfoAsn decoded)
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            decoded = default;
            AsnReader sequenceReader = reader.ReadSequence(expectedTag);

            decoded.ContentType = sequenceReader.ReadObjectIdentifierAsString();
            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(sequenceReader, out decoded.ContentEncryptionAlgorithm);

            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
            {
                if (sequenceReader.TryReadPrimitiveOctetStringBytes(new Asn1Tag(TagClass.ContextSpecific, 0), out ReadOnlyMemory <byte> tmpEncryptedContent))
                {
                    decoded.EncryptedContent = tmpEncryptedContent;
                }
                else
                {
                    decoded.EncryptedContent = sequenceReader.ReadOctetString(new Asn1Tag(TagClass.ContextSpecific, 0));
                }
            }


            sequenceReader.ThrowIfNotEmpty();
        }
예제 #11
0
        public static void VerifyMultiByteParsing(string inputHex, string expectedValue)
        {
            byte[]    inputData = inputHex.HexToByteArray();
            AsnReader reader    = new AsnReader(inputData, AsnEncodingRules.DER);

            string oidValue = reader.ReadObjectIdentifierAsString();

            Assert.Equal(expectedValue, oidValue);
        }
예제 #12
0
        public static void TagMustBeCorrect_Universal(PublicEncodingRules ruleSet)
        {
            byte[]    inputData = "06028837".HexToByteArray();
            AsnReader reader    = new AsnReader(inputData, (AsnEncodingRules)ruleSet);

            Assert.Throws <ArgumentException>(
                "expectedTag",
                () => reader.ReadIntegerBytes(Asn1Tag.Null));

            Assert.True(reader.HasData, "HasData after bad universal tag");

            Assert.Throws <CryptographicException>(
                () => reader.ReadObjectIdentifierAsString(new Asn1Tag(TagClass.ContextSpecific, 0)));

            Assert.True(reader.HasData, "HasData after wrong tag");

            Assert.Equal("2.999", reader.ReadObjectIdentifierAsString());
            Assert.False(reader.HasData, "HasData after read");
        }
예제 #13
0
        public static void ReadObjectIdentifierAsString_Success(
            PublicEncodingRules ruleSet,
            string inputHex,
            string expectedValue)
        {
            byte[]    inputData = inputHex.HexToByteArray();
            AsnReader reader    = new AsnReader(inputData, (AsnEncodingRules)ruleSet);

            string oidValue = reader.ReadObjectIdentifierAsString();

            Assert.Equal(expectedValue, oidValue);
        }
        private static void AssertExtension(AsnReader extensions, string oid, bool critical, int index, byte[] bytes)
        {
            AsnReader extension = extensions.ReadSequence();

            Assert.Equal(oid, extension.ReadObjectIdentifierAsString());

            if (critical)
            {
                Assert.True(extension.ReadBoolean(), $"{oid} is critical");
            }

            Assert.True(extension.TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory <byte> extensionBytes));
            AssertRefSame(extensionBytes, ref bytes[index], $"{oid} extension value is at byte {index}");
        }
        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out AccessDescriptionAsn decoded)
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            decoded = default;
            AsnReader sequenceReader = reader.ReadSequence(expectedTag);

            decoded.AccessMethod = sequenceReader.ReadObjectIdentifierAsString();
            System.Security.Cryptography.Asn1.GeneralNameAsn.Decode(sequenceReader, out decoded.AccessLocation);

            sequenceReader.ThrowIfNotEmpty();
        }
예제 #16
0
        public static string DecodeOid(byte[] encodedOid)
        {
            // Windows compat.
            if (s_invalidEmptyOid.AsSpan().SequenceEqual(encodedOid))
            {
                return(string.Empty);
            }

            // Read using BER because the CMS specification says the encoding is BER.
            AsnReader reader = new AsnReader(encodedOid, AsnEncodingRules.BER);
            string    value  = reader.ReadObjectIdentifierAsString();

            reader.ThrowIfNotEmpty();
            return(value);
        }
예제 #17
0
        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out PolicyQualifierInfo decoded)
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            decoded = default;
            AsnReader sequenceReader = reader.ReadSequence(expectedTag);

            decoded.PolicyQualifierId = sequenceReader.ReadObjectIdentifierAsString();
            decoded.Qualifier         = sequenceReader.GetEncodedValue();

            sequenceReader.ThrowIfNotEmpty();
        }
예제 #18
0
        private static ISet <string> ReadExtendedKeyUsageExtension(byte[] rawData)
        {
            HashSet <string> oids = new HashSet <string>();

            AsnReader reader         = new AsnReader(rawData, AsnEncodingRules.DER);
            AsnReader sequenceReader = reader.ReadSequence();

            reader.ThrowIfNotEmpty();

            //OidCollection usages
            while (sequenceReader.HasData)
            {
                oids.Add(sequenceReader.ReadObjectIdentifierAsString());
            }

            return(oids);
        }
        public override string DecodeOid(byte[] encodedOid)
        {
            // Windows compat.
            if (s_invalidEmptyOid.AsSpan().SequenceEqual(encodedOid))
            {
                return(string.Empty);
            }

            // Read using BER because the CMS specification says the encoding is BER.
            AsnReader reader = new AsnReader(encodedOid, AsnEncodingRules.BER);
            string    value  = reader.ReadObjectIdentifierAsString();

            if (reader.HasData)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
            }

            return(value);
        }
예제 #20
0
        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out SecretBagAsn decoded)
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            decoded = default;
            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
            AsnReader explicitReader;

            decoded.SecretTypeId = sequenceReader.ReadObjectIdentifierAsString();

            explicitReader      = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
            decoded.SecretValue = explicitReader.ReadEncodedValue();
            explicitReader.ThrowIfNotEmpty();


            sequenceReader.ThrowIfNotEmpty();
        }
예제 #21
0
        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out OtherKeyAttributeAsn decoded)
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            decoded = default;
            AsnReader sequenceReader = reader.ReadSequence(expectedTag);

            decoded.KeyAttrId = sequenceReader.ReadObjectIdentifierAsString();

            if (sequenceReader.HasData)
            {
                decoded.KeyAttr = sequenceReader.GetEncodedValue();
            }


            sequenceReader.ThrowIfNotEmpty();
        }
예제 #22
0
        public static void ExpectedTag_IgnoresConstructed(
            PublicEncodingRules ruleSet,
            string inputHex,
            PublicTagClass tagClass,
            int tagValue)
        {
            byte[]    inputData = inputHex.HexToByteArray();
            AsnReader reader    = new AsnReader(inputData, (AsnEncodingRules)ruleSet);

            string val1 = reader.ReadObjectIdentifierAsString(new Asn1Tag((TagClass)tagClass, tagValue, true));

            Assert.False(reader.HasData);

            reader = new AsnReader(inputData, (AsnEncodingRules)ruleSet);

            string val2 = reader.ReadObjectIdentifierAsString(new Asn1Tag((TagClass)tagClass, tagValue, false));

            Assert.False(reader.HasData);

            Assert.Equal(val1, val2);
        }
예제 #23
0
        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out SafeBagAsn decoded)
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            decoded = default;
            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
            AsnReader explicitReader;
            AsnReader collectionReader;

            decoded.BagId = sequenceReader.ReadObjectIdentifierAsString();

            explicitReader   = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
            decoded.BagValue = explicitReader.GetEncodedValue();
            explicitReader.ThrowIfNotEmpty();


            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.SetOf))
            {
                // Decode SEQUENCE OF for BagAttributes
                {
                    collectionReader = sequenceReader.ReadSetOf();
                    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.BagAttributes = tmpList.ToArray();
                }
            }


            sequenceReader.ThrowIfNotEmpty();
        }
        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out EncapsulatedContentInfoAsn decoded)
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            decoded = default;
            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
            AsnReader explicitReader;

            decoded.ContentType = sequenceReader.ReadObjectIdentifierAsString();

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


            sequenceReader.ThrowIfNotEmpty();
        }
        private static void AssertRdn(
            AsnReader reader,
            string atvOid,
            int offset,
            Asn1Tag valueTag,
            byte[] bytes,
            string label,
            string stringValue = null)
        {
            AsnReader rdn = reader.ReadSetOf();
            AsnReader attributeTypeAndValue = rdn.ReadSequence();

            Assert.Equal(atvOid, attributeTypeAndValue.ReadObjectIdentifierAsString());

            ReadOnlyMemory <byte> value     = attributeTypeAndValue.ReadEncodedValue();
            ReadOnlySpan <byte>   valueSpan = value.Span;

            Assert.True(Asn1Tag.TryDecode(valueSpan, out Asn1Tag actualTag, out int bytesRead));
            Assert.Equal(1, bytesRead);
            Assert.Equal(valueTag, actualTag);

            AssertRefSame(
                ref MemoryMarshal.GetReference(valueSpan),
                ref bytes[offset],
                $"{label} is at bytes[{offset}]");

            if (stringValue != null)
            {
                AsnReader valueReader = new AsnReader(value, AsnEncodingRules.DER);
                Assert.Equal(stringValue, valueReader.ReadCharacterString((UniversalTagNumber)valueTag.TagValue));
                Assert.False(valueReader.HasData, "valueReader.HasData");
            }

            Assert.False(attributeTypeAndValue.HasData, $"attributeTypeAndValue.HasData ({label})");
            Assert.False(rdn.HasData, $"rdn.HasData ({label})");
        }
        public static void ReadMicrosoftComCert()
        {
            byte[]    bytes      = MicrosoftDotComSslCertBytes;
            AsnReader fileReader = new AsnReader(bytes, AsnEncodingRules.DER);

            AsnReader certReader = fileReader.ReadSequence();

            Assert.False(fileReader.HasData, "fileReader.HasData");

            AsnReader tbsCertReader = certReader.ReadSequence();
            AsnReader sigAlgReader  = certReader.ReadSequence();

            Assert.True(
                certReader.TryReadPrimitiveBitStringValue(
                    out int unusedBitCount,
                    out ReadOnlyMemory <byte> signature),
                "certReader.TryGetBitStringBytes");

            Assert.Equal(0, unusedBitCount);
            AssertRefSame(signature, ref bytes[1176], "Signature is a ref to bytes[1176]");

            Assert.False(certReader.HasData, "certReader.HasData");

            AsnReader versionExplicitWrapper = tbsCertReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));

            Assert.True(versionExplicitWrapper.TryReadInt32(out int certVersion));
            Assert.Equal(2, certVersion);
            Assert.False(versionExplicitWrapper.HasData, "versionExplicitWrapper.HasData");

            ReadOnlyMemory <byte> serialBytes = tbsCertReader.ReadIntegerBytes();

            AssertRefSame(serialBytes, ref bytes[15], "Serial number starts at bytes[15]");

            AsnReader tbsSigAlgReader = tbsCertReader.ReadSequence();

            Assert.Equal("1.2.840.113549.1.1.11", tbsSigAlgReader.ReadObjectIdentifierAsString());
            Assert.True(tbsSigAlgReader.HasData, "tbsSigAlgReader.HasData before ReadNull");
            tbsSigAlgReader.ReadNull();
            Assert.False(tbsSigAlgReader.HasData, "tbsSigAlgReader.HasData after ReadNull");

            AsnReader issuerReader    = tbsCertReader.ReadSequence();
            Asn1Tag   printableString = new Asn1Tag(UniversalTagNumber.PrintableString);

            AssertRdn(issuerReader, "2.5.4.6", 57, printableString, bytes, "issuer[C]");
            AssertRdn(issuerReader, "2.5.4.10", 70, printableString, bytes, "issuer[O]");
            AssertRdn(issuerReader, "2.5.4.11", 101, printableString, bytes, "issuer[OU]");
            AssertRdn(issuerReader, "2.5.4.3", 134, printableString, bytes, "issuer[CN]");
            Assert.False(issuerReader.HasData, "issuerReader.HasData");

            AsnReader validityReader = tbsCertReader.ReadSequence();

            Assert.Equal(new DateTimeOffset(2014, 10, 15, 0, 0, 0, TimeSpan.Zero), validityReader.ReadUtcTime());
            Assert.Equal(new DateTimeOffset(2016, 10, 15, 23, 59, 59, TimeSpan.Zero), validityReader.ReadUtcTime());
            Assert.False(validityReader.HasData, "validityReader.HasData");

            AsnReader subjectReader = tbsCertReader.ReadSequence();
            Asn1Tag   utf8String    = new Asn1Tag(UniversalTagNumber.UTF8String);

            AssertRdn(subjectReader, "1.3.6.1.4.1.311.60.2.1.3", 220, printableString, bytes, "subject[EV Country]");
            AssertRdn(subjectReader, "1.3.6.1.4.1.311.60.2.1.2", 241, utf8String, bytes, "subject[EV State]", "Washington");
            AssertRdn(subjectReader, "2.5.4.15", 262, printableString, bytes, "subject[Business Category]");
            AssertRdn(subjectReader, "2.5.4.5", 293, printableString, bytes, "subject[Serial Number]");
            AssertRdn(subjectReader, "2.5.4.6", 313, printableString, bytes, "subject[C]");
            AssertRdn(subjectReader, "2.5.4.17", 326, utf8String, bytes, "subject[Postal Code]", "98052");
            AssertRdn(subjectReader, "2.5.4.8", 342, utf8String, bytes, "subject[ST]", "Washington");
            AssertRdn(subjectReader, "2.5.4.7", 363, utf8String, bytes, "subject[L]", "Redmond");
            AssertRdn(subjectReader, "2.5.4.9", 381, utf8String, bytes, "subject[Street Address]", "1 Microsoft Way");
            AssertRdn(subjectReader, "2.5.4.10", 407, utf8String, bytes, "subject[O]", "Microsoft Corporation");
            AssertRdn(subjectReader, "2.5.4.11", 439, utf8String, bytes, "subject[OU]", "MSCOM");
            AssertRdn(subjectReader, "2.5.4.3", 455, utf8String, bytes, "subject[CN]", "www.microsoft.com");
            Assert.False(subjectReader.HasData, "subjectReader.HasData");

            AsnReader subjectPublicKeyInfo = tbsCertReader.ReadSequence();
            AsnReader spkiAlgorithm        = subjectPublicKeyInfo.ReadSequence();

            Assert.Equal("1.2.840.113549.1.1.1", spkiAlgorithm.ReadObjectIdentifierAsString());
            spkiAlgorithm.ReadNull();
            Assert.False(spkiAlgorithm.HasData, "spkiAlgorithm.HasData");

            Assert.True(
                subjectPublicKeyInfo.TryReadPrimitiveBitStringValue(
                    out unusedBitCount,
                    out ReadOnlyMemory <byte> encodedPublicKey),
                "subjectPublicKeyInfo.TryGetBitStringBytes");

            Assert.Equal(0, unusedBitCount);
            AssertRefSame(encodedPublicKey, ref bytes[498], "Encoded public key starts at byte 498");

            Assert.False(subjectPublicKeyInfo.HasData, "subjectPublicKeyInfo.HasData");

            AsnReader publicKeyReader    = new AsnReader(encodedPublicKey, AsnEncodingRules.DER);
            AsnReader rsaPublicKeyReader = publicKeyReader.ReadSequence();

            AssertRefSame(rsaPublicKeyReader.ReadIntegerBytes(), ref bytes[506], "RSA Modulus is at bytes[502]");
            Assert.True(rsaPublicKeyReader.TryReadInt32(out int rsaExponent));
            Assert.Equal(65537, rsaExponent);
            Assert.False(rsaPublicKeyReader.HasData, "rsaPublicKeyReader.HasData");
            Assert.False(publicKeyReader.HasData, "publicKeyReader.HasData");

            AsnReader extensionsContainer = tbsCertReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 3));
            AsnReader extensions          = extensionsContainer.ReadSequence();

            Assert.False(extensionsContainer.HasData, "extensionsContainer.HasData");

            AsnReader sanExtension = extensions.ReadSequence();

            Assert.Equal("2.5.29.17", sanExtension.ReadObjectIdentifierAsString());
            Assert.True(sanExtension.TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory <byte> sanExtensionBytes));
            Assert.False(sanExtension.HasData, "sanExtension.HasData");

            AsnReader sanExtensionPayload = new AsnReader(sanExtensionBytes, AsnEncodingRules.DER);
            AsnReader sanExtensionValue   = sanExtensionPayload.ReadSequence();

            Assert.False(sanExtensionPayload.HasData, "sanExtensionPayload.HasData");
            Asn1Tag dnsName = new Asn1Tag(TagClass.ContextSpecific, 2);

            Assert.Equal("www.microsoft.com", sanExtensionValue.ReadCharacterString(dnsName, UniversalTagNumber.IA5String));
            Assert.Equal("wwwqa.microsoft.com", sanExtensionValue.ReadCharacterString(dnsName, UniversalTagNumber.IA5String));
            Assert.False(sanExtensionValue.HasData, "sanExtensionValue.HasData");

            AsnReader basicConstraints = extensions.ReadSequence();

            Assert.Equal("2.5.29.19", basicConstraints.ReadObjectIdentifierAsString());
            Assert.True(basicConstraints.TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory <byte> basicConstraintsBytes));

            AsnReader basicConstraintsPayload = new AsnReader(basicConstraintsBytes, AsnEncodingRules.DER);
            AsnReader basicConstraintsValue   = basicConstraintsPayload.ReadSequence();

            Assert.False(basicConstraintsValue.HasData, "basicConstraintsValue.HasData");
            Assert.False(basicConstraintsPayload.HasData, "basicConstraintsPayload.HasData");

            AsnReader keyUsageExtension = extensions.ReadSequence();

            Assert.Equal("2.5.29.15", keyUsageExtension.ReadObjectIdentifierAsString());
            Assert.True(keyUsageExtension.ReadBoolean(), "keyUsageExtension.ReadBoolean() (IsCritical)");
            Assert.True(keyUsageExtension.TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory <byte> keyUsageBytes));

            AsnReader keyUsagePayload = new AsnReader(keyUsageBytes, AsnEncodingRules.DER);

            Assert.Equal(
                X509KeyUsageCSharpStyle.DigitalSignature | X509KeyUsageCSharpStyle.KeyEncipherment,
                keyUsagePayload.ReadNamedBitListValue <X509KeyUsageCSharpStyle>());

            Assert.False(keyUsagePayload.HasData, "keyUsagePayload.HasData");

            AssertExtension(extensions, "2.5.29.37", false, 863, bytes);
            AssertExtension(extensions, "2.5.29.32", false, 894, bytes);
            AssertExtension(extensions, "2.5.29.35", false, 998, bytes);
            AssertExtension(extensions, "2.5.29.31", false, 1031, bytes);
            AssertExtension(extensions, "1.3.6.1.5.5.7.1.1", false, 1081, bytes);
            Assert.False(extensions.HasData, "extensions.HasData");

            Assert.Equal("1.2.840.113549.1.1.11", sigAlgReader.ReadObjectIdentifierAsString());
            sigAlgReader.ReadNull();
            Assert.False(sigAlgReader.HasData);
        }
        private static string X500DistinguishedNameDecode(
            byte[] encodedName,
            bool printOid,
            bool reverse,
            bool quoteIfNeeded,
            string dnSeparator,
            string multiValueSeparator,
            bool addTrailingDelimiter)
        {
            AsnReader x500NameReader         = new AsnReader(encodedName, AsnEncodingRules.DER);
            AsnReader x500NameSequenceReader = x500NameReader.ReadSequence();
            var       rdnReaders             = new List <AsnReader>();

            x500NameReader.ThrowIfNotEmpty();

            while (x500NameSequenceReader.HasData)
            {
                rdnReaders.Add(x500NameSequenceReader.ReadSetOf());
            }

            // We need to allocate a StringBuilder to hold the data as we're building it, and there's the usual
            // arbitrary process of choosing a number that's "big enough" to minimize reallocations without wasting
            // too much space in the average case.
            //
            // So, let's look at an example of what our output might be.
            //
            // GitHub.com's SSL cert has a "pretty long" subject (partially due to the unknown OIDs):
            //   businessCategory=Private Organization
            //   1.3.6.1.4.1.311.60.2.1.3=US
            //   1.3.6.1.4.1.311.60.2.1.2=Delaware
            //   serialNumber=5157550
            //   street=548 4th Street
            //   postalCode=94107
            //   C=US
            //   ST=California
            //   L=San Francisco
            //   O=GitHub, Inc.
            //   CN=github.com
            //
            // Which comes out to 228 characters using OpenSSL's default pretty-print
            // (openssl x509 -in github.cer -text -noout)
            // Throw in some "maybe-I-need-to-quote-this" quotes, and a couple of extra/extra-long O/OU values
            // and round that up to the next programmer number, and you get that 512 should avoid reallocations
            // in all but the most dire of cases.
            StringBuilder decodedName  = new StringBuilder(512);
            int           entryCount   = rdnReaders.Count;
            bool          printSpacing = false;

            for (int i = 0; i < entryCount; i++)
            {
                int loc = reverse ? entryCount - i - 1 : i;

                // RelativeDistinguishedName ::=
                //   SET SIZE (1..MAX) OF AttributeTypeAndValue
                //
                // AttributeTypeAndValue::= SEQUENCE {
                //   type AttributeType,
                //   value    AttributeValue }
                //
                // AttributeType::= OBJECT IDENTIFIER
                //
                // AttributeValue ::= ANY-- DEFINED BY AttributeType

                if (printSpacing)
                {
                    decodedName.Append(dnSeparator);
                }
                else
                {
                    printSpacing = true;
                }

                AsnReader rdnReader = rdnReaders[loc];
                bool      hadValue  = false;

                while (rdnReader.HasData)
                {
                    AsnReader tavReader      = rdnReader.ReadSequence();
                    string    oid            = tavReader.ReadObjectIdentifierAsString();
                    string    attributeValue = tavReader.ReadDirectoryOrIA5String();

                    tavReader.ThrowIfNotEmpty();

                    if (hadValue)
                    {
                        decodedName.Append(multiValueSeparator);
                    }
                    else
                    {
                        hadValue = true;
                    }

                    if (printOid)
                    {
                        AppendOid(decodedName, oid);
                    }


                    bool quote = quoteIfNeeded && NeedsQuoting(attributeValue);

                    if (quote)
                    {
                        decodedName.Append('"');

                        // If the RDN itself had a quote within it, that quote needs to be escaped
                        // with another quote.
                        attributeValue = attributeValue.Replace("\"", "\"\"");
                    }

                    decodedName.Append(attributeValue);

                    if (quote)
                    {
                        decodedName.Append('"');
                    }
                }
            }

            if (addTrailingDelimiter && decodedName.Length > 0)
            {
                decodedName.Append(dnSeparator);
            }

            return(decodedName.ToString());
        }
        internal CertificateDataAsn(byte[] rawData)
        {
            AsnReader reader = new AsnReader(rawData, AsnEncodingRules.DER).ReadSequence();

            AsnReader tbsCertificate = reader.ReadSequence();

            if (tbsCertificate.PeekTag() == explicit0)
            {
                AsnReader version = tbsCertificate.ReadSequence(explicit0);
                version.TryReadInt32(out Version);
            }
            else if (tbsCertificate.PeekTag() != Asn1Tag.Integer)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
            }
            else
            {
                Version = 0;
            }

            if (Version < 0 || Version > 2)
            {
                throw new CryptographicException();
            }

            SerialNumber = tbsCertificate.GetIntegerBytes().ToArray();

            AsnReader tbsSignature = tbsCertificate.ReadSequence();

            TbsSignature.AlgorithmId = tbsSignature.ReadObjectIdentifierAsString();
            TbsSignature.Parameters  = tbsSignature.HasData ? tbsSignature.GetEncodedValue().ToArray() : Array.Empty <byte>();

            if (tbsSignature.HasData)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
            }

            Issuer = new X500DistinguishedName(tbsCertificate.GetEncodedValue().ToArray());

            AsnReader validity = tbsCertificate.ReadSequence();

            NotBefore = validity.GetUtcTime().UtcDateTime;             // FIXME
            NotAfter  = validity.GetUtcTime().UtcDateTime;

            if (validity.HasData)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
            }

            Subject = new X500DistinguishedName(tbsCertificate.GetEncodedValue().ToArray());

            SubjectPublicKeyInfo = tbsCertificate.GetEncodedValue().ToArray();
            AsnReader subjectPublicKeyInfo = new AsnReader(SubjectPublicKeyInfo, AsnEncodingRules.DER).ReadSequence();
            AsnReader subjectKeyAlgorithm  = subjectPublicKeyInfo.ReadSequence();

            PublicKeyAlgorithm.AlgorithmId = subjectKeyAlgorithm.ReadObjectIdentifierAsString();
            PublicKeyAlgorithm.Parameters  = subjectKeyAlgorithm.HasData ? subjectKeyAlgorithm.GetEncodedValue().ToArray() : Array.Empty <byte>();

            if (subjectKeyAlgorithm.HasData)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
            }

            PublicKey = subjectPublicKeyInfo.ReadBitString();

            if (subjectPublicKeyInfo.HasData)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
            }

            if (Version > 0 &&
                tbsCertificate.HasData &&
                tbsCertificate.PeekTag() == explicit1)
            {
                IssuerUniqueId = tbsCertificate.ReadBitString();
            }
            else
            {
                IssuerUniqueId = null;
            }

            if (Version > 0 &&
                tbsCertificate.HasData &&
                tbsCertificate.PeekTag() == explicit2)
            {
                SubjectUniqueId = tbsCertificate.ReadBitString();
            }
            else
            {
                SubjectUniqueId = null;
            }

            Extensions = new List <X509Extension>();

            if (Version > 1 &&
                tbsCertificate.HasData &&
                tbsCertificate.PeekTag() == explicit3)
            {
                AsnReader extensions = tbsCertificate.ReadSequence(explicit3);
                extensions = extensions.ReadSequence();

                while (extensions.HasData)
                {
                    AsnReader extensionReader = extensions.ReadSequence();
                    string    oid             = extensionReader.ReadObjectIdentifierAsString();
                    bool      critical        = false;

                    if (extensionReader.PeekTag() == Asn1Tag.Boolean)
                    {
                        critical = extensionReader.ReadBoolean();
                    }

                    byte[] extensionData = extensionReader.ReadOctetString();

                    Extensions.Add(new X509Extension(oid, extensionData, critical));

                    if (extensionReader.HasData)
                    {
                        throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
                    }
                }
            }

            if (tbsCertificate.HasData)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
            }

            AsnReader signatureAlgorithm = reader.ReadSequence();

            SignatureAlgorithm.AlgorithmId = signatureAlgorithm.ReadObjectIdentifierAsString();
            SignatureAlgorithm.Parameters  = signatureAlgorithm.HasData ? signatureAlgorithm.GetEncodedValue().ToArray() : Array.Empty <byte>();

            if (signatureAlgorithm.HasData)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
            }

            SignatureValue = reader.ReadBitString();

            if (reader.HasData)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
            }

            RawData = rawData;
        }