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