Subject: [kitten] gss_acquire_cred_ext()

From: Luke Howard <[email-masked]>
Date: Thu, 19 May 2011 14:35:41 +0200

Folks,

We have an application requirement for an extended variant of gss_acquire_cred() that takes a set of attributes. Those attributes may indicate things as:

* a user's password
* a user's private key
* the service name
* behaviour, such as whether we prompt for credentials if required, callbacks, etc.

There are a few ways to skin this cat API-wise. Here's something to get the discussion started, suggested by Sam. For now I'm interested in coming up with an API that can let us deprecate gss_acquire_cred_with_password() (from Solaris). Additional attributes and their format we can discuss in a separate thread.

gss_const_OID GSS_CA_PASSWORD;

typedef struct gss_password_cred_attr_desc {
	gss_const_OID attribute; /* GSS_CA_PASSWORD */
	gss_buffer_desc password;
} gss_password_cred_attr_t;

typedef struct gss_cred_attr_desc {
	gss_const_OID attribute;
	/* OM_uint32 flags or int mandatory; ? */
	/* ... */
} gss_cred_attr_t;

OM_uint32
gss_acquire_cred_ext(
	OM_uint32 *minor_status,
	const gss_name_t desired_name,
	const gss_const_cred_attr_t *credential_attrs,
	int credential_attr_count,
	OM_uint32 time_req,
	gss_const_OID desired_mech,
	gss_cred_usage_t cred_usage,
	gss_cred_id_t *output_cred_handle
	);

(Note other out parameters have been removed for simplicity. You can use gss_inquire_cred() to get them.)

So you might use it like this:

acquire_cred_with_password()
{
	gss_password_cred_attr_t password = {
		GSS_CA_PASSWORD,
		{ 4, "asdf" } };
	gss_cred_attr_t attrs[] = { (gss_cred_attr_t)&password };

...

	major = gss_acquire_cred_ext(
		&minor,
		name,
		attrs,
		sizeof(attrs) / sizeof(attrs[0]),
		time_req,
		mech,
		GSS_C_INITIATE,
		&cred);
}

If you finding the casting objectionable, then we could do something like:

typedef struct gss_cred_attr_desc {
	gss_const_OID attribute;
	const void *value;
} gss_cred_attr_t;

And finally, if you don't like the gss_wrap_iov() pattern of passing the count as a function parameter, we could define a gss_cred_attr_set_t. That would be more consistent with the rest of the GSS-API but maybe marginally more work for application developers.

Let the flaming begin!

-- Luke

---

From: Nico Williams <[email-masked]>
Date: Thu, 19 May 2011 10:33:50 -0500

I'll think about this today and get back to you.

My preferred API design for this sort of thing would be to have a
function to acquire an "empty" handle, and one to add a single
attribute -- because we're likely to do that for sec contexts, I'd
like a consistent approach for credentials.  The nice thing about this
approach is that you can always add new functions to set new
attributes with data types that are different from the ones you have
in mind today.

Nico
--

---

From: Martin Rex <[email-masked]>
Date: Thu, 19 May 2011 18:16:14 +0200 (MEST)

> attributes with data types that are different from the ones you have

I think I'm currently leaning towards the approach depicted by Nico.

The primary question is about making things easy for the caller,
especially dealing with older implementations in a simple backwards
compatible fashion.

The abstract underlying problem is that an application may be
used with gss-api mechanism implementations with differing
features/characteristics, and you probably do not want to require
completely seperate code paths for the application for each
different incarnation of a gssapi mechanism implementation.

The two possible approaches are:

 (a) like existing context attributes:

     one call that takes a huge list of features of input attributes
     and returns a list of output features that were recognized/granted.
     It's up to the application caller to check whether the resulting
     list of attributes/characteristics fits the callers requirements,
     the gssapi mechanism is supposed to return a valid credentials
     if at all possible, even when none of the requested attributes
     is recognized or supported/available.

     dealing with conflicting attributes might become somewhere between
     difficult to non-predictable, like indicating which attributes are 
     more important for the caller than others.

 (b) the application itself iterates over the attributes that it likes
     for a credential handle and requests each attribute/characteristic
     seperately.  A failure leaves the credential handle as-is, and
     the error is specific to the requested attribute.  The application
     caller is automatically fully aware about which attributes are
     available and which aren't.

     An inquiry function is probably necessary to determine all attributes
     later on, or for delegated credentials handles.

-Martin

---

From: Nico Williams <[email-masked]>
Date: Thu, 19 May 2011 11:52:12 -0500

> especially dealing with older implementations in a simple backwards

I agree.  I think multiple function calls is probably less ugly than
an array of attributes, plus, if there's unsupported attributes, then
what?  A call per-attribute will make it possible to determine that
some attrs are not supported.

> different incarnation of a gssapi mechanism implementation.

Exactly.

Also, if you pass a credential to a library (think of something like
RPCSEC_GSS), then you probably want a way to set attributes more than
once.

In terms of lines of caller code, my approach is probably a bit
lengthier, but I find multiple function calls more readable than a
single call with a large array as an input.

Nico
--

---

From: Luke Howard <[email-masked]>
Date: Thu, 19 May 2011 19:33:10 +0200

Oh, like the gss_set_cred_option we have today? Maybe that's not such a bad idea...

Sent from my iPhone

---

From: Simon Josefsson <[email-masked]>
Date: Fri, 20 May 2011 11:08:37 +0200

> single call with a large array as an input.

+1

I think this approach is easier to implement in a callback environment
as well: the callback would then add the new property (e.g., password)
to the context, rather than having to add the property to an internal
list, and schedule some code to add all properties to the context once
the callback loop is over.

/Simon

---

From: Sam Hartman <[email-masked]>
Date: Fri, 27 May 2011 13:22:04 -0400

>>>>> "Nico" == Nico Williams <[email-masked]> writes:

    Nico> I'll think about this today and get back to you.  My preferred
    Nico> API design for this sort of thing would be to have a function
    Nico> to acquire an "empty" handle, and one to add a single
    Nico> attribute -- because we're likely to do that for sec contexts,
    Nico> I'd like a consistent approach for credentials.  The nice
    Nico> thing about this approach is that you can always add new
    Nico> functions to set new attributes with data types that are
    Nico> different from the ones you have in mind today.

I'm happy with this sort of approach  if we can provide a way that the
mechglue need not implement all these functions.

I agree with your general design though.
I was planning on providing a liberally licensed c++ header  with an
object for constructing the array in Luke's proposal.
I'm happy pushing more of that into the IETF provided we do so in a
manner that does not involve the mechglue needing to know about all the
attributes.