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(); }
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); }
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()); } }
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(); }