RFR 6722928: Support SSPI as a native GSS-API provider
Nico Williams
Nico.Williams at twosigma.com
Thu Dec 6 18:48:24 UTC 2018
On Wed, Dec 05, 2018 at 11:41:44AM +0800, Weijun Wang wrote:
> Java's GSSName::isMN always returns true, therefore to my observation, the
> GSS-API canonicalize_name() is not called if GSSName::canonicalize is called.
That *would* be a valid design choice (per RFCs 2743 and 2744), but it requires
always calling gss_canonicalize_name() immediately when you gss_import_name() a
string (as opposed to an exported name token).
However, to do this you have to canonicalize the name for every mechanism
indicated by gss_indicate_mechs()! And then it wouldn't be clear what to
output from toString() when the native provider supports multiple mechanisms,
so I don't recommend this design choice.
But the JGSS JNI bindings isn't actually doing any of that.
Instead the JGSS JNI bindings outright lies about the name claiming it's an MN
when it may not be. I'm not sure how much appetite we should have to fix this
sort of buglet, but it should be fixed, really.
If I'd noticed this buglet a couple of years ago then our contribution would
include a fix for it :(
> It is only called in export(), where the first call to export_name() might
(And in getKrbName(), which is used only for JAAS permissions checks.)
> return "Name is not MN" (MIT krb5 behavior) and then the bridge automatically
> call canonicalize_name() and export_name() again.
Right.
> And then, the export format is only useful when importing a NT_EXPORT_NAME.
The export name is meant for two things:
- to be able to get a stable token you can store in things like ACLs
- to be able to memcmp() for name equality, which has different semantics than
gss_compare_name()
> So, seems like both export_name() and canonicalize_name() are quite useless
> (at least in the view of the native bridge).
Exported name tokens have uses (see above), and it does work in JGSS. So
exportName is not at all useless.
canonicalizeName(), however, is pretty useless. Because
gss_canonicalize_name() is pretty useless.
gss_canonicalize_name() was originally intended so that one could write an
application that takes a user-input principal name, canonicalizes it, exports
it, and stores the exported name token in an ACL.
The problems with gss_canonicalize_name() are:
a) It can require credentials in order to talk to a directory, but there's no
input credentials handle argument.
E.g., given referrals, to properly canonicalize a name with Kerberos
requires doing TGS exchanges, which requires Kerberos client credentials.
b) A directory may be required for the canonicalization step, but none may be
available.
E.g., imagine a GSS mechanism that uses PKIX certificates... How would you
resolve a name "nico" of username name-type to something like CN=nico,...?
For some realms you could have local mapping rules configuration to do that
with, but in the general case you'd need a directory (LDAP, say), and you'd
have to know how to search it for this. There isn't always a directory that
allows these searches, and it's not always the case that certificates issued
by some CA adhere to a rigid naming convention.
Even if you use various subjectAlternativeName name types, you'd still have
canonicalization issues that might require a directory.
Oh, and searching any such directory would presumably require credentials;
see (a).
We've had a few lengthy discussions of this on the KRB-WG and KITTEN mailing
lists. And I suspect if you look you might find discussions of this in the old
CAT WG mailing list from the early- and mid-90s.
Because of its shortcomings, I'm inclined to not worry too much about
gss_canonicalize_name(), but isMN() *must not* lie, that's for sure, so in the
end I'm inclined to just fix GSSNameElement to know whether a name is an MN,
and to have a proper, public canonicalize() method that calls the native
canonicalizeName() method (and so gss_canonicalize_name()).
If you do all this then exportName() need not have that fallback code path to
call gss_canonicalize_name(). In principle it's a bug to do that because,
again, if the native GSS provider supports multiple mechanisms, which mechanism
should exportName() pick?! This sort of bug has been papered over by
supporting only Kerberos and SPNEGO, since ultimately that means supporting
only Kerberos. But there are other mechanisms that might be supported. E.g.,
MSFT has one called PKU2U that uses PKIX credentials instead of Kerberos, and
Globus has one that uses TLS for the same purpose.
> What's your ideal output? The toString of canonicalize() and import(export)
> always showing krb5 style and name type being KRB5_NAME?
In the JNI bindings toString() should always output whatever gss_display_name()
outputs. Full stop.
The effect of that, if the bindings only call gss_canonicalize_name() when the
Java canonicalize() method is called, would be this:
- if a name is not an MN, meaning it wasn't output by gss_canonicalize_name(),
gss_accept_sec_context(), gss_inquire_context(), or gss_import_name() of a
GSS_C_NT_EXPORTED_NAME token, then toString() should return the original
name from the gss_import_name() call (the GSSNameElement constructor);
- otherwise (if a name is an MN), then toString() should return the output of
gss_display_name() as applied to the MN
If the JNI bindings were to aggressively call gss_canonicalize_name() early,
then you'd have to choose a mechanism whose name display form to output in
toString() (see above).
Nico
--
More information about the security-dev
mailing list