internal static SafeSharedAsn1ObjectHandle GetX509NameEntryOid(SafeSharedX509NameEntryHandle nameEntry) { CheckValidOpenSslHandle(nameEntry); SafeSharedAsn1ObjectHandle handle = GetX509NameEntryOid_private(nameEntry); if (!handle.IsInvalid) { handle.SetParent(nameEntry); } return(handle); }
internal static string GetOidValue(SafeSharedAsn1ObjectHandle asn1Object) { Debug.Assert(asn1Object != null); bool added = false; asn1Object.DangerousAddRef(ref added); try { return(GetOidValue(asn1Object.DangerousGetHandle())); } finally { asn1Object.DangerousRelease(); } }
internal static string X500DistinguishedNameDecode( byte[] encodedName, bool printOid, X500DistinguishedNameFlags flags) { bool reverse = (flags & X500DistinguishedNameFlags.Reversed) == X500DistinguishedNameFlags.Reversed; bool quoteIfNeeded = (flags & X500DistinguishedNameFlags.DoNotUseQuotes) != X500DistinguishedNameFlags.DoNotUseQuotes; string dnSeparator; if ((flags & X500DistinguishedNameFlags.UseSemicolons) == X500DistinguishedNameFlags.UseSemicolons) { dnSeparator = "; "; } else if ((flags & X500DistinguishedNameFlags.UseNewLines) == X500DistinguishedNameFlags.UseNewLines) { dnSeparator = Environment.NewLine; } else { // This is matching Windows (native) behavior, UseCommas does not need to be asserted, // it is just what happens if neither UseSemicolons nor UseNewLines is specified. dnSeparator = ", "; } using (SafeX509NameHandle x509Name = Interop.Crypto.DecodeX509Name(encodedName, encodedName.Length)) { if (x509Name.IsInvalid) { return(""); } // 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 = Interop.Crypto.GetX509NameEntryCount(x509Name); bool printSpacing = false; for (int i = 0; i < entryCount; i++) { int loc = reverse ? entryCount - i - 1 : i; using (SafeSharedX509NameEntryHandle nameEntry = Interop.Crypto.GetX509NameEntry(x509Name, loc)) { Interop.Crypto.CheckValidOpenSslHandle(nameEntry); string thisOidValue; using (SafeSharedAsn1ObjectHandle oidHandle = Interop.Crypto.GetX509NameEntryOid(nameEntry)) { thisOidValue = Interop.Crypto.GetOidValue(oidHandle); } if (printSpacing) { decodedName.Append(dnSeparator); } else { printSpacing = true; } if (printOid) { AppendOid(decodedName, thisOidValue); } string rdnValue; using (SafeSharedAsn1StringHandle valueHandle = Interop.Crypto.GetX509NameEntryData(nameEntry)) { rdnValue = Interop.Crypto.Asn1StringToManagedString(valueHandle); } bool quote = quoteIfNeeded && NeedsQuoting(rdnValue); if (quote) { decodedName.Append('"'); // If the RDN itself had a quote within it, that quote needs to be escaped // with another quote. rdnValue = rdnValue.Replace("\"", "\"\""); } decodedName.Append(rdnValue); if (quote) { decodedName.Append('"'); } } } return(decodedName.ToString()); } }