Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for X509_NAME_print_ex(3) #1688

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

overhacked
Copy link

@overhacked overhacked commented Sep 13, 2022

Fixes #1637, by adding two methods:

  • X509NameRef.format_bytes()
  • X509NameRef.format()

format_bytes() is a proxy for X509_NAME_print_ex(3), just renamed to Rust vernacular. For a more ergonomic API in the most common use case, format() modifies the flags passed by the caller to ensure that OpenSSL returns UTF-8 output, then converts the BIO bytes returned to a Rust String.

Tests included ensure that:

  • The most commonly-used flags, as taken from the OpenSSL man page, return expected output
  • The special case of XN_FLAG_COMPAT works as expected
  • Printing the name of a certificate with Unicode characters, emoji in this case, functions with both format() and format_bytes()

@overhacked overhacked changed the title Add support for X509_name_print_ex(3) Add support for X509_NAME_print_ex(3) Sep 13, 2022
@overhacked overhacked force-pushed the fix_1637 branch 3 times, most recently from a5c0b7c to 3dc2f1e Compare July 28, 2023 13:05
@overhacked
Copy link
Author

overhacked commented Jul 28, 2023

I'd love to get this merged, but it currently fails under the unstable BoringSSL support. bssl-sys incorrectly types the XN_FLAG_* macros as i32 when they are actually c_ulong. I handled this in openssl-sys by adding constant definitions to openssl-sys/src/x509.rs, but bssl-sys is upstream?

This could be handled for bssl-sys by using the bindgen::callbacks::ParseCallbacks::int_macro API, but that would only work for #[feature(bindgen)], because the int_macro callback isn't exposed in the bindgen CLI.

@sfackler
Copy link
Owner

You can define a cfg-dependant type for the flags, like we do in a few other places:

#[cfg(boringssl)]
type LenType = libc::size_t;
#[cfg(not(boringssl))]
type LenType = libc::c_int;

@overhacked overhacked force-pushed the fix_1637 branch 2 times, most recently from 31082ee to 3dc2f1e Compare August 1, 2023 23:03
@overhacked
Copy link
Author

I'd love to get the X509_NAME_print_ex support merged, even if it only works on non-BoringSSL builds until the upstream bug is fixed or somehow mitigated. I put some effort into figuring out how to mitigate, without success. Detailed notes follow.

Mitigation possibilities

openssl-sys doesn't control the declaration of the constant, it gets it from bssl-sys. Changing the type of the constant to u32 wouldn't help, anyway, because the BoringSSL API function (X509_NAME_print_ex) expects flags as a c_ulong. I opened an upstream bug for BoringSSL, because bssl-sys needs to solve the issue either 1️⃣ the same way openssl-sys does, by omitting constants from bindgen and maintaining them by hand, or 2️⃣ by using the ParseCallbacks::int_macro API to change the type of selected groups of macro constants.

I tried an approach to override the const types like openssl-sys does for OpenSSL and LibreSSL. That won't work with bssl_sys, because the glob re-exports conflict (rustc seems to omit the const symbol in the exported library).

An alternate solution would be to drop the use of bssl-sys altogether, and use only the bindgen code that currently only gets hit when building on a system where the default SSL is BoringSSL and feature unstable_boringssl is disabled. That would allow using the ParseCallbacks API (or even using hand-rolled consts) with BoringSSL, BUT the "bindgen CLI" building approach would have to be dropped, because the CLI doesn't support ParseCallbacks::int_macro.

I don't understand why there is a feature = "bindgen" and not(feature = "bindgen") way of calling bindgen for BoringSSL. Don't they both depend on bindgen but in different ways? I'll admit I'm far from deep enough into rust-openssl development to know for sure.

@sfackler
Copy link
Owner

sfackler commented Aug 3, 2023

What about the thing I suggested?

@overhacked
Copy link
Author

I don’t think the cfg-gated type aliases will work, because the function signature is the same for both OpenSSL and BoringSSL. The API isn’t different, just bssl-sys generates the wrong type for the macro-defined constants.

I submitted a patch to BoringSSL… https://boringssl-review.googlesource.com/c/boringssl/+/62146

@davidben
Copy link
Contributor

davidben commented Feb 14, 2024

Ultimately the constants are due to a bindgen bug and should be fixed there. Alas there doesn't seem to be any movement in fixing that, so we'll have to workaround it. I've got a CL in flight to fix it in a way that'll work a bit better for us. (Reproducible builds are important to us, so the build.rs mess is a bit of a problem.)

That said, I would recommend rejecting this PR. This project has gotten into trouble before with using the various string-based OpenSSL APIs, and this is introducing yet more of them. Most of the flags this PR proposes to export are pretty incoherent. One even changes the return value convention of a function.

If you must encode a name as a string, I'd suggest sticking to the RFC encoding, as that's the only well-defined one. Even then, that encoding is not injective. Different names will give the same string encoding. It is also not even stable across OpenSSL versions! The encoding can change as they add support for new OIDs types because they cross-reference it against the whole OID table. (Probably not a good idea.) So at minimum, the API should come with a suitable warning about when it is and isn't safe to use.

Adds two methods:

* `X509NameRef.format_bytes()`
* `X509NameRef.format()`

`format_bytes()` is a proxy for `X509_name_print_ex(3)`, just renamed to
Rust vernacular. For a more ergonomic API in the most common use case,
`format()` modifies the flags passed by the caller to ensure that
OpenSSL returns UTF-8 output, then converts the BIO bytes returned to a
Rust `String`.

Tests included ensure that:

* The most commonly-used flags, as taken from
the OpenSSL man page, return expected output
* The special case of `XN_FLAG_COMPAT` works as expected
* Printing the name of a certificate with Unicode characters, emoji in
  this case, functions with both `format()` and `format_bytes()`
Not supported by LibreSSL. Not supported < `ossl110`
bitflags no longer derives traits by default, so `Clone, Copy,
PartialEq, Eq` need to be derived outside the macro, per
<https://docs.rs/bitflags/2.5.0/bitflags/#custom-derives>.

Signed-off-by: Ross Williams <ross@ross-williams.net>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

X509_name_print_ex unsupported
3 participants