Evaluation part 1 of JDK-6722928: Provide a default native GSS-API library on Windows

Weijun Wang weijun.wang at oracle.com
Tue Apr 21 13:36:47 UTC 2020



> On Apr 2, 2020, at 12:21 AM, Osipov, Michael <michael.osipov at siemens.com> wrote:
> 
> Hi Max,
> 
> at last I took some time to evaluate you SSPI bridge. This is part one. Interaction evaluation will follow in a second email.
> 
> Assumptions:
> * All methods, objects behave the same as with JGSS
> * AcceptSecurityContext is not implemented so should everything associated with it fail (GSSException)
> * Code analysis happens based on https://github.com/AdoptOpenJDK/openjdk-jdk13u/blob/master/src/java.security.jgss/windows/native/libsspi_bridge/sspi.cpp
> and zulu13.29.9-ca-jdk13.0.2-win_x64
> 
> Findings C:
> * sspi.cpp: Would it make sense to replace "__declspec(dllexport)" with JNIEXPORT?

This is not a JNI library. It's a GSS-API native library.

> * GSSManager#createCredential(): I'd expect an exception when *not* GSSCredential.INITIATE_ONLY is requested/passed

Yes, it should fail.

> * sspi.cpp#L67-L68: Feels a bit awkward to permit SSPI_BRIDGE_TRACE="". Why not have "if (trace && *trace)"?

I think it's harmless but if every C program has that style I can follow.

> * sspi.cpp#L233: The function name says "show_oid", but I see no OID printed. Simply symbolic names.

Yes, it should be more like "what is this OID?". I'll think of a better name.

> * sspi.cpp#L290: Empty string check? like (realm && *realm)

But then it's still L"".

> * Usage of %p: If you don't know that %p is used it is hard to tell why this output is there. May turn to "at 0x%p" in general?

OK.

Most of the debug messages are used during my coding, and not really useful for a customer. Maybe I should do a cleanup.

> * sspi.cpp#L359: -2!= reads awkward. Reformat?

A space is needed.

> * sspi.cpp#L482-L483: This is highly questionable. While it is true for Windows, it does not stick to gss_compare_name behavior. Don't know what the correct approach would be here.

I'll be glad if it's always true for Windows. I found the name thing most complicated, and here it's still only simple name and not UPN...

> * sspi.cpp#L595: That's weird. A string leads to a length? Should it read: PP("Name found: %ls -> %s [%d]", names, buffer, len)

Sorry, I'll reformat. As I said, these messages are really not so useful for customers.

> * sspi.cpp#L618: You are resetting cred_usage passed with the function. This looks like a bug to me.

It's more like I ignore it. Will double check.

> * sspi.cpp#L619: Reads very bad, maybe turn into "PP("AcquireCredentialsHandle with usage: %d, creds: 0x%p", cred_usage, desired_mechs)"

OK.

> * sspi.cpp#L627-L633: Trace message could be more expressive, e.g., "Requesting Kerberos mech"

Yes, this is something that might really be useful.

> * sspi.cpp#L657-L658 and sspi.cpp#L687-L688: They look wrong and do not correspond to GSSCredentialImpl.java#L628-L640. default value should be INITIATE_AND_ACCEPT.

Oh, I'll check.

>  Same as in GSS-API:
> $ sudo python3
> > Python 3.7.7 (default, Mar 19 2020, 21:26:00)
> > [Clang 9.0.1 (git at github.com:llvm/llvm-project.git c1a0a213378a458fbea1a5c77b31 on freebsd12
> > Type "help", "copyright", "credits" or "license" for more information.
> > >>> import gssapi
> > >>> cred = gssapi.Credentials(usage='nonsense')
> > >>> cred.usage
> > 'both'
> This also may be a bug in py-gssapi/MIT Kerberos
> * sspi.cpp#L149
> ** Can you apply a better output like ISO 8601? In strftime(3) that would be "%FT%T, ..."

I'll check, but the current format is most readable for me.

> ** "%uld" does not seem to work here: 4294967295ld. Shouldn't that read "%"PRIu32" seconds" or "%lu seconds"?

Oh.

> * sspi.cpp#L744: "Comparison result: %d". You are not comparing the result, but print comparsion result.

OK.

> * sspi.cpp#L841: man 3 gss_import_sec_context says: GSS_S_UNAVAILABLE

I'm using GSS_S_FAILURE everywhere. I know it's not precise.

> * sspi.cpp#L977-L979: Not helpful when the SEC_E_* not mapped to major/minor. This likely applies to most mapping functions.

???

> * sspi.cpp#L1012: Maybe: "Names: client: %s, server: %s"?

OK.

> * sspi.cpp#L1046: Maybe like gss_export_sec_context?

Not sure what you want me to do.

> * sspi.cpp#L1169: Remove word "IMPLEMENTED"

Oops.

> * sspi.cpp#L1169: Maybe like gss_export_sec_context?

???

> * sspi.cpp#L1480: Includes a trailing, redundant newline

Oops.

> * sspi.cpp#L729-L748: Why do you do this? The documentation for parameter 1 says: If the process that requests the handle does not have access to the credentials, the function returns an error. I have verified this with py-win32: win32security.AcquireCredentialsHandle(). Infact, it accepts any principal and always returns the default one. I found these:
> ** https://github.com/twosigma/gsskrb5/blob/master/krb5/krb5cred.c#L127-L132
> ** https://github.com/twosigma/gsskrb5/blob/master/krb5/krb5cred.c#L127-L132
> > >>> cred, time = win32security.AcquireCredentialsHandle("Administrator at ORACLE.COM", "Kerberos", win32security.SECPKG_CRED_OUTBOUND, None, None)
> > >>> cred.QueryCredentialsAttributes(1)
> > 'osipovmi at AD001.SIEMENS.NET'

Is this the expected result?

> 
> 
> Findings Java:
> * GssManager#createCredential() with ACCEPT_ONLY or INITIATE_AND_ACCEPT gives me weird credentials with partial null nembers. I'd expect an exception here.

Oops. Will look into. Maybe I should reject.

> * This is one fails, but shall work:
> > GSSManager manager = GSSManager.getInstance();
> > GSSName userName = manager.createName("osipovmi", GSSName.NT_USER_NAME);
> > GSSCredential cred = manager.createCredential(userName, GSSCredential.DEFAULT_LIFETIME, krb5Oid, GSSCredential.INITIATE_ONLY);
> > [SSPI:1627] >>>> Calling gss_create_empty_oid_set...
> > [SSPI:1542] >>>> Calling gss_add_oid_set_member...
> > [SSPI:612] >>>> Calling gss_acquire_cred...
> > [SSPI:619] AcquireCredentialsHandle with 0 00000257FFB199B0
> > [SSPI:262] gss_OID_set.count is 1
> > [SSPI:237] Kerberos mech
> > [SSPI:628] reqKerberos
> > [SSPI:152] cred expiration: 09/13/30828  04:48 4294967295ld
> > [SSPI:732] Acquiring cred with a name. Check if it's me.
> > [SSPI:791] >>>> Calling gss_inquire_cred...
> > [SSPI:811] Allocate new name at 00000257FFB2BC40
> > [SSPI:428] >>>> Calling gss_compare_name...
> > [SSPI:437] Comparing osipovmi at AD001.SIEMENS.NET and osipovmi
> > [SSPI:325] >>>> Calling gss_release_name 00000257FFB17830...
> > [SSPI:744] Comparing result: 0
> > [SSPI:767] >>>> Calling gss_release_cred...
> > [SSPI:1641] >>>> Calling gss_release_oid_set...
> > Exception in thread "main" GSSException: Failure unspecified at GSS-API level
> > 	at java.security.jgss/sun.security.jgss.wrapper.GSSLibStub.acquireCred(Native Method)
> 
> The problem is that I provide a local name and expect the default realm to be used. It seems like #createCredential() does not take that into account. It also has no avail when the canonicalized form is used. See sspi.cpp#L729-L748.
> * GssManager#createContext(GSSCredential) still works although this should be a acceptor context. I expect an expception. Does not fail with JGSS either. MIT Kerberos with py-gssapi properly fails:
> > >>> cred = gssapi.Credentials(usage='accept')                                   >>> cred
> > <gssapi.creds.Credentials object at 0x80164bbb0>
> > >>> context = gssapi.SecurityContext(usage='initiate', creds=cred, name=canon_name, mech=gssapi.MechType.kerberos)
> > >>> context.step(None)
> > Traceback (most recent call last):
> >   File "<stdin>", line 1, in <module>
> >   File "<decorator-gen-15>", line 2, in step
> >   File "/usr/local/lib/python3.7/site-packages/gssapi/_utils.py", line 167, in check_last_err
> >     return func(self, *args, **kwargs)
> >   File "<decorator-gen-5>", line 2, in step
> >   File "/usr/local/lib/python3.7/site-packages/gssapi/_utils.py", line 127, in catch_and_return_token
> >     return func(self, *args, **kwargs)
> >   File "/usr/local/lib/python3.7/site-packages/gssapi/sec_contexts.py", line 521, in step
> >     return self._initiator_step(token=token)
> >   File "/usr/local/lib/python3.7/site-packages/gssapi/sec_contexts.py", line 542, in _initiator_step
> >     token)
> >   File "gssapi/raw/sec_contexts.pyx", line 245, in gssapi.raw.sec_contexts.init_sec_context
> > gssapi.raw.exceptions.MissingCredentialsError: Major (458752): Es wurden keine Anmeldedaten übergeben oder die Anmeldedaten waren nicht verfügbar bzw. ein Zugriff darauf nicht möglich., Minor (100001): Unknown code 0

This looks bad, I'll try it myself. First I'll need to install a Windows VirtualBox guest...

Thanks,
Max

> 
> That's it for now.
> 
> Michael




More information about the security-dev mailing list