Example #1
0
        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory <byte> rebind, out CadesIssuerSerial decoded)
        {
            decoded = default;
            AsnValueReader      sequenceReader = reader.ReadSequence(expectedTag);
            AsnValueReader      collectionReader;
            ReadOnlySpan <byte> rebindSpan = rebind.Span;
            int offset;
            ReadOnlySpan <byte> tmpSpan;


            // Decode SEQUENCE OF for Issuer
            {
                collectionReader = sequenceReader.ReadSequence();
                var            tmpList = new List <GeneralNameAsn>();
                GeneralNameAsn tmpItem;

                while (collectionReader.HasData)
                {
                    GeneralNameAsn.Decode(ref collectionReader, rebind, out tmpItem);
                    tmpList.Add(tmpItem);
                }

                decoded.Issuer = tmpList.ToArray();
            }

            tmpSpan = sequenceReader.ReadIntegerBytes();
            decoded.SerialNumber = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();

            sequenceReader.ThrowIfNotEmpty();
        }
Example #2
0
        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");

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

            reader.ThrowIfNotEmpty();

            while (sequenceReader.HasData)
            {
                GeneralNameAsn.Decode(sequenceReader, 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
                        AsnReader nameReader = new AsnReader(generalName.OtherName.Value.Value, 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;
                }
            }

            return(null);
        }
Example #3
0
        private static byte[] Encode(
            Oid policyId,
            Oid hashAlgorithmId,
            ReadOnlyMemory <byte> messageHash,
            ReadOnlyMemory <byte> serialNumber,
            DateTimeOffset timestamp,
            bool isOrdering,
            long?accuracyInMicroseconds,
            ReadOnlyMemory <byte>?nonce,
            ReadOnlyMemory <byte>?tsaName,
            X509ExtensionCollection?extensions)
        {
            if (policyId == null)
            {
                throw new ArgumentNullException(nameof(policyId));
            }
            if (hashAlgorithmId == null)
            {
                throw new ArgumentNullException(nameof(hashAlgorithmId));
            }

            var tstInfo = new Rfc3161TstInfo
            {
                // The only legal value as of 2017.
                Version        = 1,
                Policy         = policyId,
                MessageImprint =
                {
                    HashAlgorithm  =
                    {
                        Algorithm  = hashAlgorithmId,
                        Parameters = AlgorithmIdentifierAsn.ExplicitDerNull,
                    },

                    HashedMessage  = messageHash,
                },
                SerialNumber = serialNumber,
                GenTime      = timestamp,
                Ordering     = isOrdering,
                Nonce        = nonce,
            };

            if (accuracyInMicroseconds != null)
            {
                tstInfo.Accuracy = new Rfc3161Accuracy(accuracyInMicroseconds.Value);
            }

            if (tsaName != null)
            {
                tstInfo.Tsa = GeneralNameAsn.Decode(tsaName.Value, AsnEncodingRules.DER);
            }

            if (extensions != null)
            {
                tstInfo.Extensions = extensions.OfType <X509Extension>().
                                     Select(ex => new X509ExtensionAsn(ex)).ToArray();
            }

            using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER))
            {
                tstInfo.Encode(writer);
                return(writer.Encode());
            }
        }
Example #4
0
        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();
                AsnReader     reader           = new AsnReader(rawData, AsnEncodingRules.DER);
                AsnReader     collectionReader = reader.ReadSequence();

                reader.ThrowIfNotEmpty();

                while (collectionReader.HasData)
                {
                    GeneralNameAsn.Decode(collectionReader, 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 (CryptographicException)
            {
                return(null);
            }
        }
        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();
            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))
            {
                Rfc3161Accuracy tmpAccuracy;
                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));
                GeneralNameAsn tmpTsa;
                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 <X509ExtensionAsn>();
                    X509ExtensionAsn tmpItem;

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

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


            sequenceReader.ThrowIfNotEmpty();
        }