Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

NetFX compatibility fixes for X500DistinguishedName. #30572

Merged
merged 12 commits into from
Jun 24, 2018

Conversation

filipnavara
Copy link
Member

@filipnavara filipnavara commented Jun 21, 2018

@filipnavara filipnavara changed the title WIP: NetFX compatibility fixes for X500DistinguishedName. NetFX compatibility fixes for X500DistinguishedName. Jun 21, 2018
@filipnavara
Copy link
Member Author

@bartonjs, can you review please?

@@ -51,7 +51,7 @@ internal static partial class X500NameEncoder
{
dnSeparator = "; ";
}
else if ((flags & X500DistinguishedNameFlags.UseNewLines) == X500DistinguishedNameFlags.UseNewLines)
else if ((flags & (X500DistinguishedNameFlags.UseNewLines | X500DistinguishedNameFlags.UseCommas)) == X500DistinguishedNameFlags.UseNewLines)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a comment to explain that explicit commas beats newline, but that commas are the implicit default.

new object[]
{
"CN=GrapeCity inc., OU=Tools Development, O=GrapeCity inc., L=Sendai Izumi-ku, S=Miyagi, C=JP",
"308186310b3009060355040613024a50310f300d060355040813064d6979616769311830160603550407130f53656e64616920497a756d692d6b7531173015060355040a140e47726170654369747920696e632e311a3018060355040b1411546f6f6c7320446576656c6f706d656e74311730150603550403140e47726170654369747920696e632e"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please break these long constants up into multiple lines.

// Mono test case taken from old bug report
new object[]
{
"SERIALNUMBER=CVR:13471967-UID:121212121212, E=vhm@use.test.dk, CN=Hedeby's Møbelhandel - Salgsafdelingen, O=Hedeby's Møbelhandel // CVR:13471967, C=DK",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know how reliably o-slash is going to roundtrip through various git clients and text editors. Please replace it with \u00d8.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point!

// Technically the T.61 encoding (code page 20261) should be used here, but many
// implementations don't follow that and use ISO 8859-1 instead. This matches the
// behavior of CryptoAPI on NetFX (https://github.com/dotnet/corefx/issues/27466).
string t61String = System.Text.Encoding.GetEncoding("ISO-8859-1").GetString(_data, _position, contentLength);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm guessing that it's actually Windows-1252, or, more transparently:

char[] chars = new char[contentLength];

for (int i = 0; i < contentLength; i++)
{
    chars[i] = (char)_data[_position + i];
}

string t61string = new string(chars);

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually tried couple of 1252 characters on Windows that are missing in iso-8859-1 and they were missing from the output.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds like a test to add 😄

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Turns out it is neither 1252 nor iso-8859-1. Windows actually interprets it as UTF-8. I will add test case for that.

new object[]
{
"CN=\u00A2",
"300D310B300906035504061402C2A2"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0603550406 is "2.5.4.6" => id-countryName ("C=", not "CN=").

@bartonjs
Copy link
Member

on macOS the "Møbelhandel" didn't decode correctly (it got a FFFD replacement character).

So maybe it's something more nuanced. UTF-8 unless it had a decode error (e.g. had to add an FFFD), and Windows-1252 otherwise.

Looks like, maybe, this could be

private static Text.Encoding MakeT61Encoding()
{
    // Using Clone() allows DecoderFallback to be assigned.
    var utf8 = Text.Encoding.Utf8.Clone();
    utf8.DecoderFallback = new TheFallbackWouldHaveToBeWritten();
    // Until further need.
    utf8.EncoderFallback = EncoderFallback.ExceptionFallback;
}

Or

s_t61Utf8 = new Utf8Encoding(false, true);

try
{
    s_t61Utf8.GetWhatever(...);
}
catch (DecoderFallbackException)
{
    bytes-to-chars it is, then();
}

depending on if the fallback is "whole string" or "per character".

@filipnavara
Copy link
Member Author

Looks like macOS is not the only problematic one. The OpenSSL decoder fails on the UTF-8 string. It could be easier to just find out what OpenSSL does and mimic that instead of Windows.

@filipnavara
Copy link
Member Author

The NETFX test failure is unrelated to the changes.

new object[]
{
"C=\u00C2\u00A2",
"300D310B300906035504061402C2A2"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if the payload had a UTF-8 multi-byte character followed by an invalid UTF-8 sequence?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

300E310C300A06035504071403C2A2F8 -> L=墿 (https://dotnetfiddle.net/ERdAyB), will add it to the tests

[Theory]
[MemberData(nameof(T61CasesLatin1))]
[PlatformSpecific(TestPlatforms.AnyUnix & ~TestPlatforms.OSX)]
public static void T61StringsLatin1(string expected, string hexEncoded)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'm fine with dumping X500NameEncoder.OpenSslDecode.cs as part of this change, and just using the same managed implementation on macOS and Linux. It'll cut down on a lot of SafeHandles and P/Invokes, as well as unify the behaviors.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do.

@bartonjs
Copy link
Member

@dotnet-bot Test NETFX x86 Release Build please (now that #30565 has merged and X509Certificates tests are enabled for netfx)

try
{
var utf8 = (System.Text.Encoding)System.Text.Encoding.UTF8.Clone();
utf8.DecoderFallback = System.Text.DecoderFallback.ExceptionFallback;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be simplified to new Utf8Encoding(false, true) since it's using the ExceptionFallback.

I'd probably promote this and the ISO-8859-1 encoding objects to statics, no strong opinion on fieldinit or LazyInitializer.EnsureInitialized or just if (s_utf8WithExceptionsEncoding == null) { s_utf8WithExceptionsEncoding = new Utf8Encoding(false, true); }

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't use new Utf8Encoding(false, true) the first time because of the additional reference to System.Text.Encoding.Extensions. LazyInitializer.EnsureInitialized seems like a reasonable option since it's already used elsewhere in the class.

@bartonjs
Copy link
Member

Aside from the last comment about the two Encoding objects I think I'm happy with it. @stephentoub would you mind giving it a once-over?

Copy link
Member

@stephentoub stephentoub left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other than the one issue about not creating a new Encoding for each use, LGTM.

@bartonjs bartonjs merged commit 5e3aecf into dotnet:master Jun 24, 2018
@bartonjs
Copy link
Member

Thanks, @filipnavara :)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants