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

Code review of ts jgss jdk12 #1

Draft
wants to merge 25 commits into
base: jdk12-master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
0b47709
Add missing dbgsysGetLastErrorString()
Nov 10, 2015
e7b31c2
JGSS: Fix cut/paste error in NativeUtil.c
Sep 20, 2018
003d82b
Fix error handling in GSSLibStub
Sep 21, 2018
0191c79
Implement String to gss_buffer_t import
Sep 21, 2018
f8d26b3
Revert initGSSBuffer to JDK7 non-copy behaviour
Nov 12, 2015
2a9e744
Fix loss of GSS_S_FAILURE major status in importContext
Nov 11, 2015
e2ad2c5
Add actual mechanism to native GSSNameElement state
Dec 9, 2015
63dcbe5
Add getLocalName() GSSName method
nicowilliams Mar 1, 2016
a742c8e
Add createCredential() with password
nicowilliams Nov 11, 2015
d975a3d
JGSS: Don't dispose() of creds too eagerly
nicowilliams Aug 16, 2018
561e7f4
Fix SpNego multi-round-trip bug
nicowilliams Aug 16, 2018
5840bfd
JGSS: Add comment about unnec. perm check
nicowilliams Aug 15, 2018
ac1f706
ServicePermission empty realm support
nicowilliams Dec 4, 2015
837a750
Add isDefaultCredential() method to GSSCredentialSpi
nicowilliams Dec 4, 2015
173c04b
JGSS: Prefer default cred handles if possible
nicowilliams Dec 4, 2015
b7cd095
Make GSSName implement Principal (add getName())
nicowilliams Dec 4, 2015
89341f8
Add GssLoginModule
nicowilliams Oct 8, 2015
98f952f
Engage GssLoginModule (only) when native=true
nicowilliams Mar 11, 2016
78a7cac
Krb5LoginModule cleanup
nicowilliams Mar 8, 2016
5a494b0
fixup SEAM bug uncomments
nicowilliams Aug 14, 2018
ac27524
Fix leak in exception cases in getJavaOID()
nicowilliams Aug 14, 2018
90d3097
FIXME commentary
nicowilliams Dec 5, 2015
5a541ee
Add commentary about permissions checks
nicowilliams Sep 27, 2018
192cc47
JGSS: Simplify context permissions checks
nicowilliams Sep 26, 2018
16f33b3
Dispose of delegated cred handles early
nicowilliams Sep 27, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -214,10 +214,48 @@ public boolean implies(Permission p) {


boolean impliesIgnoreMask(ServicePermission p) {
return ((this.getName().equals("*")) ||
this.getName().equals(p.getName()) ||
(p.getName().startsWith("@") &&
this.getName().endsWith(p.getName())));
if ((this.getName().equals("*")) ||
this.getName().equals(p.getName()) ||
(p.getName().startsWith("@") &&
this.getName().endsWith(p.getName())))
return true;

/*
* Empty realm in this or p is a wild-card. This is needed to support
* non-Kerberos ServicePermissions for GSS (a band-aid until we can
* implement a proper GssAcceptorPermission class), but also because
* users may not know and might not care what realm the service is in,
* especially when they are using a keytab.
*
* If the user is using a password, then the realm matters more. An
* untrusted actor could cause KDCs for a realm they control to see
* material they could attack offline, but that was already the case
* anyways, and the answer is the same in all cases: use stronger
* passwords, use randomized keys in a keytab, or let us implement
* SPAKE or similar alternatives to the venerable PA-ENC-TIMESTAMP.
*/
if ((this.getName().equals("krbtgt/@") &&
p.getName().startsWith("krbtgt/")) ||
(p.getName().equals("krbtgt/@") &&
this.getName().startsWith("krbtgt/")))
return true;

char[] n = this.getName().toCharArray();
Copy link
Member Author

Choose a reason for hiding this comment

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

Converting this to a char[] is an unnecessary copy. Just operate on the String directly.

int i;
for (i = 0; i < n.length; i++) {
if (n[i] == '\\') {
i++;
continue;
}
if (n[i] == '@') {
String s = new String(n, 0, i + 1);
Copy link
Member Author

Choose a reason for hiding this comment

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

This allocation is unnecessary. Use String#regionMatches instead.

Copy link
Member

Choose a reason for hiding this comment

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

Ok.

Copy link
Member

Choose a reason for hiding this comment

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

Ok.

return (p.getName().startsWith(s) &&
(p.getName().equals(s) || this.getName().equals(s)));
}
}

// No realm, not even empty -> fail
return false;
}

/**
Expand Down
110 changes: 110 additions & 0 deletions src/java.security.jgss/share/classes/org/ietf/jgss/GSSManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,58 @@ public abstract GSSCredential createCredential (GSSName name,
int lifetime, Oid mech, int usage)
throws GSSException;

/**
* Factory method for acquiring a single mechanism credential with a
* password.<p>
*
* GSS-API mechanism providers must impose a local access-control
* policy on callers to prevent unauthorized callers from acquiring
* credentials to which they are not entitled. The kinds of permissions
* needed by different mechanism providers will be documented on a
* per-mechanism basis. A failed permission check might cause a {@link
* java.lang.SecurityException SecurityException} to be thrown from
* this method. <p>
*
* Non-default values for lifetime cannot always be honored by the
* underlying mechanisms, thus applications should be prepared to call
* {@link GSSCredential#getRemainingLifetime() getRemainingLifetime}
* on the returned credential.<p>
*
* @param name the name of the principal for whom this credential is to be
* acquired. Use <code>null</code> to specify the default principal.
* @param lifetime The number of seconds that credentials should remain
* valid. Use {@link GSSCredential#INDEFINITE_LIFETIME
* GSSCredential.INDEFINITE_LIFETIME} to request that the credentials
* have the maximum permitted lifetime. Use {@link
* GSSCredential#DEFAULT_LIFETIME GSSCredential.DEFAULT_LIFETIME} to
* request default credential lifetime.
* @param mech the Oid of the desired mechanism. Use <code>(Oid) null
* </code> to request the default mechanism.
* @param usage The intended usage for this credential object. The value
* of this parameter must be one of:
* {@link GSSCredential#INITIATE_AND_ACCEPT
* GSSCredential.INITIATE_AND_ACCEPT},
* {@link GSSCredential#ACCEPT_ONLY GSSCredential.ACCEPT_ONLY}, and
* {@link GSSCredential#INITIATE_ONLY GSSCredential.INITIATE_ONLY}.
* @return a GSSCredential of the requested type.
*
* @see GSSCredential
*
* @throws GSSException containing the following
* major error codes:
* {@link GSSException#BAD_MECH GSSException.BAD_MECH},
* {@link GSSException#BAD_NAMETYPE GSSException.BAD_NAMETYPE},
* {@link GSSException#BAD_NAME GSSException.BAD_NAME},
* {@link GSSException#CREDENTIALS_EXPIRED
* GSSException.CREDENTIALS_EXPIRED},
* {@link GSSException#NO_CRED GSSException.NO_CRED},
* {@link GSSException#FAILURE GSSException.FAILURE}
*/
public abstract GSSCredential createCredential (GSSName name,
String password, int lifetime, Oid mech,

Choose a reason for hiding this comment

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

Shouldn't the password be a char array?

Copy link
Member

Choose a reason for hiding this comment

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

Why should it be a char array and not a String?

Choose a reason for hiding this comment

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

To securely wipe the password from memory against immutable strings in Java. In C you can safely to memset with zero, you Java you can't.

Copy link
Member

Choose a reason for hiding this comment

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

Ahh, ok.

Copy link
Member

Choose a reason for hiding this comment

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

Is that reliable? @pburka suggests that a copying GC can easily leave copies of a password lying about. And in the JAAS case the password would come from a file that is read in and parsed, so there will be a number of copies. I'm not keen on reading the whole file as a char[] just so we could wipe the password.

Choose a reason for hiding this comment

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

What file are you talking about? With JAAS you have callback handlers and they use char arrays too.

Copy link
Member

Choose a reason for hiding this comment

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

Oh, maybe I was confused. Krb5LoginModule let's you specify a raw secret key -- that's a bit crazy, IMO. Still, other login modules use String for passwords too -- at least JndiLoginModule.

Choose a reason for hiding this comment

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

How if I look at this?

Copy link
Member

Choose a reason for hiding this comment

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

From src/jdk.security.auth/share/classes/com/sun/security/auth/module/JndiLoginModule.java

543                 // check the password
544                 if (verifyPassword
545                     (encryptedPassword, new String(password)) == true) {
...
710     /**
711      * Verify a password against the encrypted passwd from /etc/shadow
712      */
713     private boolean verifyPassword(String encryptedPassword, String password) {
...

Choose a reason for hiding this comment

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

Ok, I see, that's ugly. You'll see a lot of such things in the JDK. Old Code (TM).

int usage)
throws GSSException;

/**
* Factory method for acquiring credentials over a set of
* mechanisms. This method attempts to acquire credentials for
Expand Down Expand Up @@ -480,6 +532,64 @@ public abstract GSSCredential createCredential(GSSName name,
int lifetime, Oid mechs[], int usage)
throws GSSException;

/**
* Factory method for acquiring credentials with a password over a set of
* mechanisms. This method attempts to acquire credentials for
* each of the mechanisms specified in the array called mechs. To
* determine the list of mechanisms for which the acquisition of
* credentials succeeded, the caller should use the {@link
* GSSCredential#getMechs() GSSCredential.getMechs} method.<p>
*
* GSS-API mechanism providers must impose a local access-control
* policy on callers to prevent unauthorized callers from acquiring
* credentials to which they are not entitled. The kinds of permissions
* needed by different mechanism providers will be documented on a
* per-mechanism basis. A failed permission check might cause a {@link
* java.lang.SecurityException SecurityException} to be thrown from
* this method.<p>
*
* Non-default values for lifetime cannot always be honored by the
* underlying mechanisms, thus applications should be prepared to call
* {@link GSSCredential#getRemainingLifetime() getRemainingLifetime}
* on the returned credential.<p>
*
* @param name the name of the principal for whom this credential is to
* be acquired. Use <code>null</code> to specify the default
* principal.
* @param lifetime The number of seconds that credentials should remain
* valid. Use {@link GSSCredential#INDEFINITE_LIFETIME
* GSSCredential.INDEFINITE_LIFETIME} to request that the credentials
* have the maximum permitted lifetime. Use {@link
* GSSCredential#DEFAULT_LIFETIME GSSCredential.DEFAULT_LIFETIME} to
* request default credential lifetime.
* @param mechs an array of Oid's indicating the mechanisms over which
* the credential is to be acquired. Use <code>(Oid[]) null</code> for
* requesting a system specific default set of mechanisms.
* @param usage The intended usage for this credential object. The value
* of this parameter must be one of:
* {@link GSSCredential#INITIATE_AND_ACCEPT
* GSSCredential.INITIATE_AND_ACCEPT},
* {@link GSSCredential#ACCEPT_ONLY GSSCredential.ACCEPT_ONLY}, and
* {@link GSSCredential#INITIATE_ONLY GSSCredential.INITIATE_ONLY}.
* @return a GSSCredential of the requested type.
*
* @see GSSCredential
*
* @throws GSSException containing the following
* major error codes:
* {@link GSSException#BAD_MECH GSSException.BAD_MECH},
* {@link GSSException#BAD_NAMETYPE GSSException.BAD_NAMETYPE},
* {@link GSSException#BAD_NAME GSSException.BAD_NAME},
* {@link GSSException#CREDENTIALS_EXPIRED
* GSSException.CREDENTIALS_EXPIRED},
* {@link GSSException#NO_CRED GSSException.NO_CRED},
* {@link GSSException#FAILURE GSSException.FAILURE}
*/
public abstract GSSCredential createCredential(GSSName name,
String password, int lifetime,

Choose a reason for hiding this comment

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

Same here.

Oid mechs[], int usage)
throws GSSException;

/**
* Factory method for creating a context on the initiator's
* side.
Expand Down
33 changes: 32 additions & 1 deletion src/java.security.jgss/share/classes/org/ietf/jgss/GSSName.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
*/

package org.ietf.jgss;
import java.security.Principal;

/**
* This interface encapsulates a single GSS-API principal entity. The
Expand Down Expand Up @@ -102,7 +103,7 @@
* @author Mayank Upadhyay
* @since 1.4
*/
public interface GSSName {
public interface GSSName extends Principal {

/**
* Oid indicating a host-based service name form. It is used to
Expand Down Expand Up @@ -261,6 +262,16 @@ public interface GSSName {
*/
public byte[] export() throws GSSException;

/**
* Returns a local username form of a mechanism name, if available.
*/
public String getLocalName() throws GSSException;

/**
* Returns a local username form of a mechanism name, if available.
*/
public String getLocalName(Oid mech) throws GSSException;

/**
* Returns a textual representation of the <code>GSSName</code> object. To retrieve
* the printed name format, which determines the syntax of the returned
Expand All @@ -271,6 +282,26 @@ public interface GSSName {
*/
public String toString();

/**
* Returns a textual representation of the <code>GSSName</code> object.
*
* If <code>this</code> is not an MN then the returned name should be the
* same as the generic name used to construct it. Otherwise the returned
* name may be a mechanism-specific name string.
*
* @return a String representing this name in printable form.
*/
public String getName();

/**
* Returns a textual representation of the <code>GSSName</code> object
* element corresponding to the given <code>mech</code>. This will be a
* mechanism-specific representation of <code>this</code.
*
* @return a String representing this name in printable form.
*/
public String getName(Oid mech) throws GSSException;

/**
* Returns the name type of the printable
* representation of this name that can be obtained from the <code>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,17 +66,33 @@ protected GSSCredentialImpl(GSSCredentialImpl src) {
}

GSSCredentialImpl(GSSManagerImpl gssManager, GSSName name,
int lifetime, Oid mech, int usage)
int lifetime, Oid mech, int usage)
throws GSSException {
if (mech == null) mech = ProviderList.DEFAULT_MECH_OID;

init(gssManager);
add(name, lifetime, lifetime, mech, usage);
String password = null;
add(name, password, lifetime, lifetime, mech, usage);
}

GSSCredentialImpl(GSSManagerImpl gssManager, GSSName name, String password,
int lifetime, Oid mech, int usage)
throws GSSException {
if (mech == null) mech = ProviderList.DEFAULT_MECH_OID;

init(gssManager);
add(name, password, lifetime, lifetime, mech, usage);
}

GSSCredentialImpl(GSSManagerImpl gssManager, GSSName name,
int lifetime, Oid[] mechs, int usage)
throws GSSException {
this(gssManager, name, (String)null, lifetime, mechs, usage);
}

GSSCredentialImpl(GSSManagerImpl gssManager, GSSName name,
String password, int lifetime, Oid mechs[], int usage)
throws GSSException {
init(gssManager);
boolean defaultList = false;
if (mechs == null) {
Expand All @@ -86,7 +102,7 @@ protected GSSCredentialImpl(GSSCredentialImpl src) {

for (int i = 0; i < mechs.length; i++) {
try {
add(name, lifetime, lifetime, mechs[i], usage);
add(name, password, lifetime, lifetime, mechs[i], usage);
} catch (GSSException e) {
if (defaultList) {
// Try the next mechanism
Expand Down Expand Up @@ -417,6 +433,13 @@ public Oid[] getMechs() throws GSSException {

public void add(GSSName name, int initLifetime, int acceptLifetime,
Oid mech, int usage) throws GSSException {
String password = null;
add(name, password, initLifetime, acceptLifetime, mech, usage);
}

public void add(GSSName name, String password, int initLifetime,
int acceptLifetime, Oid mech, int usage)
throws GSSException {

if (destroyed) {
throw new IllegalStateException("This credential is " +
Expand All @@ -437,6 +460,7 @@ public void add(GSSName name, int initLifetime, int acceptLifetime,
((GSSNameImpl)name).getElement(mech));

tempCred = gssManager.getCredentialElement(nameElement,
password,
initLifetime,
acceptLifetime,
mech,
Expand Down Expand Up @@ -474,11 +498,20 @@ public void add(GSSName name, int initLifetime, int acceptLifetime,
key = new SearchKey(mech, currentUsage);
hashtable.put(key, tempCred);

tempCred = gssManager.getCredentialElement(nameElement,
initLifetime,
acceptLifetime,
mech,
desiredUsage);
if (password == null) {
tempCred = gssManager.getCredentialElement(nameElement,
initLifetime,
acceptLifetime,
mech,
desiredUsage);
} else {
tempCred = gssManager.getCredentialElement(nameElement,
password,
initLifetime,
acceptLifetime,
mech,
desiredUsage);
}

key = new SearchKey(mech, desiredUsage);
hashtable.put(key, tempCred);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,12 +135,26 @@ public GSSCredential createCredential(GSSName aName,
return wrap(new GSSCredentialImpl(this, aName, lifetime, mech, usage));
}

public GSSCredential createCredential(GSSName aName, String password,

Choose a reason for hiding this comment

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

Same here.

int lifetime, Oid mech, int usage)
throws GSSException {
return new GSSCredentialImpl(this, aName, password,
lifetime, mech, usage);
}

public GSSCredential createCredential(GSSName aName,
int lifetime, Oid[] mechs, int usage)
throws GSSException {
return wrap(new GSSCredentialImpl(this, aName, lifetime, mechs, usage));
}

public GSSCredential createCredential(GSSName aName, String password,
int lifetime, Oid mechs[], int usage)
throws GSSException {
return new GSSCredentialImpl(this, aName, password,
lifetime, mechs, usage);
}

public GSSContext createContext(GSSName peer, Oid mech,
GSSCredential myCred, int lifetime)
throws GSSException {
Expand Down Expand Up @@ -175,6 +189,17 @@ public GSSCredentialSpi getCredentialElement(GSSNameSpi name, int initLifetime,
acceptLifetime, usage);
}

public GSSCredentialSpi getCredentialElement(GSSNameSpi name,
String password,
int initLifetime,
int acceptLifetime,
Oid mech, int usage)
throws GSSException {
MechanismFactory factory = list.getMechFactory(mech);
return factory.getCredentialElement(name, password, initLifetime,
acceptLifetime, usage);
}

// Used by java SPNEGO impl
public GSSNameSpi getNameElement(String name, Oid nameType, Oid mech)
throws GSSException {
Expand Down
Loading