aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKazuki Yamaguchi <k@rhe.jp>2017-09-03 12:28:30 +0900
committerKazuki Yamaguchi <k@rhe.jp>2017-09-03 17:58:24 +0900
commit27c055b839cc736f7d6e41c099bc712be10ffe65 (patch)
tree29daf99fff9a9868c2a130806aa9a54a875d577f
parent58964733f7d1f9646ecc344d127150aa7115760e (diff)
downloadruby-openssl-27c055b839cc736f7d6e41c099bc712be10ffe65.tar.gz
x509name: add OpenSSL::X509::Name#to_utf8
The existing #to_s does not interact well with distinguished names containing multi-byte UTF-8 characters since the OpenSSL function X509_NAME_print_ex() escapes bytes with MSB set by default. Unfortunately we can't fix it without breaking backwards compatibility. It takes options as a bit field that is directly passed to X509_NAME_print_ex(). Let's add a new method instead. Fixes: https://github.com/ruby/openssl/issues/26
-rw-r--r--ext/openssl/ossl_x509name.c16
-rw-r--r--test/test_x509name.rb37
2 files changed, 53 insertions, 0 deletions
diff --git a/ext/openssl/ossl_x509name.c b/ext/openssl/ossl_x509name.c
index f0bbda41..86dbab18 100644
--- a/ext/openssl/ossl_x509name.c
+++ b/ext/openssl/ossl_x509name.c
@@ -305,6 +305,21 @@ ossl_x509name_to_s(int argc, VALUE *argv, VALUE self)
}
/*
+ * call-seq;
+ * name.to_utf8 -> string
+ *
+ * Returns an UTF-8 representation of the distinguished name, as specified
+ * in {RFC 2253}[https://www.ietf.org/rfc/rfc2253.txt].
+ */
+static VALUE
+ossl_x509name_to_utf8(VALUE self)
+{
+ VALUE str = x509name_print(self, XN_FLAG_RFC2253 & ~ASN1_STRFLGS_ESC_MSB);
+ rb_enc_associate_index(str, rb_utf8_encindex());
+ return str;
+}
+
+/*
* call-seq:
* name.to_a => [[name, data, type], ...]
*
@@ -498,6 +513,7 @@ Init_ossl_x509name(void)
rb_define_method(cX509Name, "initialize_copy", ossl_x509name_initialize_copy, 1);
rb_define_method(cX509Name, "add_entry", ossl_x509name_add_entry, -1);
rb_define_method(cX509Name, "to_s", ossl_x509name_to_s, -1);
+ rb_define_method(cX509Name, "to_utf8", ossl_x509name_to_utf8, 0);
rb_define_method(cX509Name, "to_a", ossl_x509name_to_a, 0);
rb_define_method(cX509Name, "cmp", ossl_x509name_cmp, 1);
rb_define_alias(cX509Name, "<=>", "cmp");
diff --git a/test/test_x509name.rb b/test/test_x509name.rb
index c9864063..ce370415 100644
--- a/test/test_x509name.rb
+++ b/test/test_x509name.rb
@@ -356,6 +356,43 @@ class OpenSSL::TestX509Name < OpenSSL::TestCase
assert_equal("CN=unya,OU=b+OU=a,O=ruby-lang", dn.dup.to_s(OpenSSL::X509::Name::RFC2253))
end
+ def test_to_s
+ dn = [
+ ["DC", "org"],
+ ["DC", "ruby-lang"],
+ ["CN", "フー, バー"],
+ ]
+ name = OpenSSL::X509::Name.new
+ dn.each { |x| name.add_entry(*x) }
+
+ assert_equal "/DC=org/DC=ruby-lang/" \
+ "CN=\\xE3\\x83\\x95\\xE3\\x83\\xBC, \\xE3\\x83\\x90\\xE3\\x83\\xBC",
+ name.to_s
+ # OpenSSL escapes characters with MSB by default
+ assert_equal \
+ "CN=\\E3\\83\\95\\E3\\83\\BC\\, \\E3\\83\\90\\E3\\83\\BC," \
+ "DC=ruby-lang,DC=org",
+ name.to_s(OpenSSL::X509::Name::RFC2253)
+ assert_equal "DC = org, DC = ruby-lang, " \
+ "CN = \"\\E3\\83\\95\\E3\\83\\BC, \\E3\\83\\90\\E3\\83\\BC\"",
+ name.to_s(OpenSSL::X509::Name::ONELINE)
+ end
+
+ def test_to_utf8
+ dn = [
+ ["DC", "org"],
+ ["DC", "ruby-lang"],
+ ["CN", "フー, バー"],
+ ]
+ name = OpenSSL::X509::Name.new
+ dn.each { |x| name.add_entry(*x) }
+
+ str = name.to_utf8
+ expected = "CN=フー\\, バー,DC=ruby-lang,DC=org".force_encoding("UTF-8")
+ assert_equal expected, str
+ assert_equal Encoding.find("UTF-8"), str.encoding
+ end
+
def test_equals2
n1 = OpenSSL::X509::Name.parse 'CN=a'
n2 = OpenSSL::X509::Name.parse 'CN=a'