internal static string FindHttpAiaRecord(byte[] authorityInformationAccess, string recordTypeOid) { DerSequenceReader reader = new DerSequenceReader(authorityInformationAccess); while (reader.HasData) { DerSequenceReader innerReader = reader.ReadSequence(); // If the sequence's first element is a sequence, unwrap it. if (innerReader.PeekTag() == ConstructedSequenceTagId) { innerReader = innerReader.ReadSequence(); } Oid oid = innerReader.ReadOid(); if (StringComparer.Ordinal.Equals(oid.Value, recordTypeOid)) { string uri = innerReader.ReadIA5String(); Uri parsedUri; if (!Uri.TryCreate(uri, UriKind.Absolute, out parsedUri)) { continue; } if (!StringComparer.Ordinal.Equals(parsedUri.Scheme, "http")) { continue; } return(uri); } } return(null); }
private static int ReadInhibitAnyPolicyExtension(X509Extension extension) { DerSequenceReader reader = DerSequenceReader.CreateForPayload(extension.RawData); return(reader.ReadInteger()); }
internal CertificateData(byte[] rawData) { #if DEBUG try { #endif DerSequenceReader reader = new DerSequenceReader(rawData); DerSequenceReader tbsCertificate = reader.ReadSequence(); if (tbsCertificate.PeekTag() == DerSequenceReader.ContextSpecificConstructedTag0) { DerSequenceReader version = tbsCertificate.ReadSequence(); Version = version.ReadInteger(); } else if (tbsCertificate.PeekTag() != (byte)DerSequenceReader.DerTag.Integer) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } else { Version = 0; } if (Version < 0 || Version > 2) { throw new CryptographicException(); } SerialNumber = tbsCertificate.ReadIntegerBytes(); DerSequenceReader tbsSignature = tbsCertificate.ReadSequence(); TbsSignature.AlgorithmId = tbsSignature.ReadOidAsString(); TbsSignature.Parameters = tbsSignature.HasData ? tbsSignature.ReadNextEncodedValue() : Array.Empty <byte>(); if (tbsSignature.HasData) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } Issuer = new X500DistinguishedName(tbsCertificate.ReadNextEncodedValue()); DerSequenceReader validity = tbsCertificate.ReadSequence(); NotBefore = validity.ReadX509Date(); NotAfter = validity.ReadX509Date(); if (validity.HasData) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } Subject = new X500DistinguishedName(tbsCertificate.ReadNextEncodedValue()); SubjectPublicKeyInfo = tbsCertificate.ReadNextEncodedValue(); DerSequenceReader subjectPublicKeyInfo = new DerSequenceReader(SubjectPublicKeyInfo); DerSequenceReader subjectKeyAlgorithm = subjectPublicKeyInfo.ReadSequence(); PublicKeyAlgorithm.AlgorithmId = subjectKeyAlgorithm.ReadOidAsString(); PublicKeyAlgorithm.Parameters = subjectKeyAlgorithm.HasData ? subjectKeyAlgorithm.ReadNextEncodedValue() : 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() == DerSequenceReader.ContextSpecificConstructedTag1) { IssuerUniqueId = tbsCertificate.ReadBitString(); } else { IssuerUniqueId = null; } if (Version > 0 && tbsCertificate.HasData && tbsCertificate.PeekTag() == DerSequenceReader.ContextSpecificConstructedTag2) { SubjectUniqueId = tbsCertificate.ReadBitString(); } else { SubjectUniqueId = null; } Extensions = new List <X509Extension>(); if (Version > 1 && tbsCertificate.HasData && tbsCertificate.PeekTag() == DerSequenceReader.ContextSpecificConstructedTag3) { DerSequenceReader extensions = tbsCertificate.ReadSequence(); extensions = extensions.ReadSequence(); while (extensions.HasData) { DerSequenceReader extensionReader = extensions.ReadSequence(); string oid = extensionReader.ReadOidAsString(); bool critical = false; if (extensionReader.PeekTag() == (byte)DerSequenceReader.DerTag.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); } DerSequenceReader signatureAlgorithm = reader.ReadSequence(); SignatureAlgorithm.AlgorithmId = signatureAlgorithm.ReadOidAsString(); SignatureAlgorithm.Parameters = signatureAlgorithm.HasData ? signatureAlgorithm.ReadNextEncodedValue() : 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; #if DEBUG } catch (Exception e) { throw new CryptographicException( $"Error in reading certificate:{Environment.NewLine}{PemPrintCert(rawData)}", e); } #endif }
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"); // SubjectAltName ::= GeneralNames // // IssuerAltName ::= GeneralNames // // GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName // // GeneralName ::= CHOICE { // otherName [0] OtherName, // rfc822Name [1] IA5String, // dNSName [2] IA5String, // x400Address [3] ORAddress, // directoryName [4] Name, // ediPartyName [5] EDIPartyName, // uniformResourceIdentifier [6] IA5String, // iPAddress [7] OCTET STRING, // registeredID [8] OBJECT IDENTIFIER } // // OtherName::= SEQUENCE { // type - id OBJECT IDENTIFIER, // value[0] EXPLICIT ANY DEFINED BY type - id } byte expectedTag = (byte)(DerSequenceReader.ContextSpecificTagFlag | (byte)matchType); if (matchType == GeneralNameType.OtherName) { expectedTag |= DerSequenceReader.ConstructedFlag; } DerSequenceReader altNameReader = new DerSequenceReader(extensionBytes); while (altNameReader.HasData) { if (altNameReader.PeekTag() != expectedTag) { altNameReader.SkipValue(); continue; } switch (matchType) { case GeneralNameType.OtherName: { DerSequenceReader otherNameReader = altNameReader.ReadSequence(); string oid = otherNameReader.ReadOidAsString(); if (oid == otherOid) { // Payload is value[0] EXPLICIT, meaning // a) it'll be tagged as ContextSpecific0 // b) that's interpretable as a Sequence (EXPLICIT) // c) the payload will then be retagged as the correct type (EXPLICIT) if (otherNameReader.PeekTag() != DerSequenceReader.ContextSpecificConstructedTag0) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } otherNameReader = otherNameReader.ReadSequence(); // Currently only UPN is supported, which is a UTF8 string per // https://msdn.microsoft.com/en-us/library/ff842518.aspx return(otherNameReader.ReadUtf8String()); } // If the OtherName OID didn't match, move to the next entry. continue; } case GeneralNameType.Rfc822Name: case GeneralNameType.DnsName: case GeneralNameType.UniformResourceIdentifier: return(altNameReader.ReadIA5String()); default: altNameReader.SkipValue(); continue; } } return(null); }
private static string GetCdpUrl(X509Certificate2 cert) { byte[] crlDistributionPoints = null; foreach (X509Extension extension in cert.Extensions) { if (StringComparer.Ordinal.Equals(extension.Oid.Value, Oids.CrlDistributionPoints)) { // If there's an Authority Information Access extension, it might be used for // looking up additional certificates for the chain. crlDistributionPoints = extension.RawData; break; } } if (crlDistributionPoints == null) { return null; } // CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint // // DistributionPoint ::= SEQUENCE { // distributionPoint [0] DistributionPointName OPTIONAL, // reasons [1] ReasonFlags OPTIONAL, // cRLIssuer [2] GeneralNames OPTIONAL } // // DistributionPointName ::= CHOICE { // fullName [0] GeneralNames, // nameRelativeToCRLIssuer [1] RelativeDistinguishedName } // // GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName // // GeneralName ::= CHOICE { // otherName [0] OtherName, // rfc822Name [1] IA5String, // dNSName [2] IA5String, // x400Address [3] ORAddress, // directoryName [4] Name, // ediPartyName [5] EDIPartyName, // uniformResourceIdentifier [6] IA5String, // iPAddress [7] OCTET STRING, // registeredID [8] OBJECT IDENTIFIER } DerSequenceReader cdpSequence = new DerSequenceReader(crlDistributionPoints); while (cdpSequence.HasData) { const byte ContextSpecificFlag = 0x80; const byte ContextSpecific0 = ContextSpecificFlag; const byte ConstructedFlag = 0x20; const byte ContextSpecificConstructed0 = ContextSpecific0 | ConstructedFlag; const byte GeneralNameUri = ContextSpecificFlag | 0x06; DerSequenceReader distributionPointReader = cdpSequence.ReadSequence(); byte tag = distributionPointReader.PeekTag(); // Only distributionPoint is supported if (tag != ContextSpecificConstructed0) { continue; } // The DistributionPointName is a CHOICE, not a SEQUENCE, but the reader is the same. DerSequenceReader dpNameReader = distributionPointReader.ReadSequence(); tag = dpNameReader.PeekTag(); // Only fullName is supported, // nameRelativeToCRLIssuer is for LDAP-based lookup. if (tag != ContextSpecificConstructed0) { continue; } DerSequenceReader fullNameReader = dpNameReader.ReadSequence(); while (fullNameReader.HasData) { tag = fullNameReader.PeekTag(); if (tag != GeneralNameUri) { fullNameReader.SkipValue(); continue; } string uri = fullNameReader.ReadIA5String(); Uri parsedUri = new Uri(uri); if (!StringComparer.Ordinal.Equals(parsedUri.Scheme, "http")) { continue; } return uri; } } return null; }
internal static byte[] DecodeX509SubjectKeyIdentifierExtension(byte[] encoded) { DerSequenceReader reader = DerSequenceReader.CreateForPayload(encoded); return(reader.ReadOctetString()); }
private static string X500DistinguishedNameDecode( byte[] encodedName, bool printOid, bool reverse, bool quoteIfNeeded, string dnSeparator, string multiValueSeparator, bool addTrailingDelimiter) { DerSequenceReader x500NameReader = new DerSequenceReader(encodedName); var rdnReaders = new List <DerSequenceReader>(); while (x500NameReader.HasData) { rdnReaders.Add(x500NameReader.ReadSet()); } // 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; } DerSequenceReader rdnReader = rdnReaders[loc]; bool hadValue = false; while (rdnReader.HasData) { DerSequenceReader tavReader = rdnReader.ReadSequence(); if (hadValue) { decodedName.Append(multiValueSeparator); } else { hadValue = true; } if (printOid) { AppendOid(decodedName, tavReader.ReadOidAsString()); } else { tavReader.SkipValue(); } string attributeValue = ReadString(tavReader); 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()); }
private static string GetCdpUrl(X509Certificate2 cert) { byte[] crlDistributionPoints = null; foreach (X509Extension extension in cert.Extensions) { if (StringComparer.Ordinal.Equals(extension.Oid.Value, Oids.CrlDistributionPoints)) { // If there's an Authority Information Access extension, it might be used for // looking up additional certificates for the chain. crlDistributionPoints = extension.RawData; break; } } if (crlDistributionPoints == null) { return(null); } // CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint // // DistributionPoint ::= SEQUENCE { // distributionPoint [0] DistributionPointName OPTIONAL, // reasons [1] ReasonFlags OPTIONAL, // cRLIssuer [2] GeneralNames OPTIONAL } // // DistributionPointName ::= CHOICE { // fullName [0] GeneralNames, // nameRelativeToCRLIssuer [1] RelativeDistinguishedName } // // GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName // // GeneralName ::= CHOICE { // otherName [0] OtherName, // rfc822Name [1] IA5String, // dNSName [2] IA5String, // x400Address [3] ORAddress, // directoryName [4] Name, // ediPartyName [5] EDIPartyName, // uniformResourceIdentifier [6] IA5String, // iPAddress [7] OCTET STRING, // registeredID [8] OBJECT IDENTIFIER } DerSequenceReader cdpSequence = new DerSequenceReader(crlDistributionPoints); while (cdpSequence.HasData) { const byte ContextSpecificFlag = 0x80; const byte ContextSpecific0 = ContextSpecificFlag; const byte ConstructedFlag = 0x20; const byte ContextSpecificConstructed0 = ContextSpecific0 | ConstructedFlag; const byte GeneralNameUri = ContextSpecificFlag | 0x06; DerSequenceReader distributionPointReader = cdpSequence.ReadSequence(); byte tag = distributionPointReader.PeekTag(); // Only distributionPoint is supported if (tag != ContextSpecificConstructed0) { continue; } // The DistributionPointName is a CHOICE, not a SEQUENCE, but the reader is the same. DerSequenceReader dpNameReader = distributionPointReader.ReadSequence(); tag = dpNameReader.PeekTag(); // Only fullName is supported, // nameRelativeToCRLIssuer is for LDAP-based lookup. if (tag != ContextSpecificConstructed0) { continue; } DerSequenceReader fullNameReader = dpNameReader.ReadSequence(); while (fullNameReader.HasData) { tag = fullNameReader.PeekTag(); if (tag != GeneralNameUri) { fullNameReader.SkipValue(); continue; } string uri = fullNameReader.ReadIA5String(); Uri parsedUri = new Uri(uri); if (!StringComparer.Ordinal.Equals(parsedUri.Scheme, "http")) { continue; } return(uri); } } return(null); }