Subject: Re: Some technical issues on Java binding

From: Mayank Upadhyay <[email-masked]>
Date: Tue, 6 Apr 1999 11:12:40 -0700 (PDT)

Hi Michael,

Here is my response to some of the issues you raised. Jack Kabat will also
be sending mail in response to some of the other issues. Hope this helps.

Regards,
Mayank

On Fri, 26 Mar 1999, Michael Smith wrote:

> 1) Mapping things with output parameters is always
> a little untidy in Java. Jack and I adopted slightly 
> different approaches to the problem of multiple 
> outputs from per-message calls (wrap/unwrap, 
> get/verify MIC). His proposal requires the caller 
> of these functions to get an instance of the class 
> MessageProp, setting the QOP and the privacy-requested 
> flag in the constructor, and then pass this as a 
> parameter to the per-message calls. Inside these 
> calls, other member values of the MessageProp object
> are set (e.g. actual QOP, privacy, token-related
> flags, etc.). When the call returns, the caller can 
> then read these values from the MessageProp object. 

The return value from wrap/unwrap/getMIC is the output buffer.  We did not
want to stick that payload into a return structure. If you do that then
the output buffer field in it becomes redundant in the case where the user
specifies streams for input and output. 

Moreover, the user can just allocate one MessageProp object and use that
all the time to pass in and get back QOP, privacy, and other information,
so its not big deal. 

> 2) As far as I can tell, Jack's functions only 
> return major and minor status when an exception is 
> thrown; otherwise, "no news is good news". We took 
> the approach of breaking out major and minor status, 
> as well as token flags, and output byte arrays for 
> tokens, into a separate interface, GSSStatus; our 
> GSSException contains one of these, a good many 
> functions have it as their return type, and the 
> PerMessageCallResult (alluded to above) extends it. 
> 
> It seemed to us that "status" of the call is 
> conceptually separate from exceptionality, and 
> potentially useful even where there is nothing 
> "exceptional"; hence the distinction. (Also, of 
> course, our status carries output tokens too, and 
> thus has significant freight even when all the
> status lights are green.)  
> 

The major status codes that GSS-API returns are nicely grouped by the RFC
into FATAL and INFORMATORY categories in Table 1 of
draft-ietf-cat-rfc2078bis-08.txt. 

In light of the fact that Java has an "Exception" mechanism in place I
would like to keep all fatal error codes in exceptions only. As a Java
programmer, I would expect to catch an exception if a fatal error occurs. 
The exception contains both the major and the minor status code.

Leaving GSS_S_COMPLETE and GSS_S_CONTINUE_NEEDED aside for the moment,
getting an informatory status code during context establishment will also
result in an exception because they are fatal when returned from
GSS_Init_sec_context() and GSS_Accept_sec_context. 

That leaves the informatory status codes from GSS_Unwrap() and
GSS_VerifyMIC(). The equivalent of the informatory major code is returned
in the MessageProp object for the caller to query. However, I realize that
in this case there is no way to indicate a minor status code. That could
easliy be added to MessageProp. 

As for GSS_S_COMPLETE and GSS_S_CONTINUE_NEEDED, the former is implicit
when no exception is thrown, and the latter is part of the state of the
context, not the individual unwrap/verifyMIC calls. (RFC page 65:
GSS_S_CONTINUE_NEEDED should be returned only by GSS_Init_sec_context() 
and GSS_Accept_sec_context()). This state of the context is returned by
Context.isEstablished() in the Java bindings. 

> 3) We have two different classes, GSSMechName   
> (corresponding to "name for mechanism") and GSSname
> (corresponding to plain old name). The former
> extends the latter, and adds the method export()
> (which is only valid for a "name for mechanism").
> GSSName has a method which takes a mechanism OID  
> as a parameter and disgorges a GSSMechName
> (the method is canonicalize(), which of course 
> represents the mapping of GSS_Canonicalize_name).
> Jack's approach is not to have different classes;
> he has a single class, GSSName, an instance of
> which may either correspond to a "name for
> mechanism" or not. If so, then export() is
> valid; if not, not (and export() presumably
> throws an exception if called). A GSSName is
> a "name for mechanism," in Jack's mapping, if   
> its constructor was called with a mechoid
> parameter, or if the method "canonicalize" was
> called subsequent to the object's creation;

The GSSName constructor is equivalent to GSS_Import_name(). It takes an
OID to indicate which nametype the object belongs to. Sometimes the
nametype is GSS_C_NT_EXPORT_NAME in which case the resulting name object
has to be an MN. If not, you can call canonicalize() on this name with a
mechanism OID. That's pretty straightforward, not roundabout. 

> that is, canonicalize(), in Jack's approach, 
> operates "in place". I presume the way one 

GSSName.canonicalize() returns a name object that is an MN. It's not "in
place", if that bothers you.

The draft also has a utility constructor that will take a mechanism OID in
addition to the nametype OID and do the GSS_Import_name and
GSS_Canonicalize_name in one shot for you to create an MN. 

As for subclassing GSSName for MN's like you suggested, the problem is
that your GSSName constructor which is the equivalent of GSS_Import_name() 
cannot then take GSS_C_NT_EXPORT_NAME as a nametype OID and expect to
morph the GSSName object it creates into a GSSMechName subclass object.
What you can do is use comnpisition where the GSSName might contain one or
more GSSMechNames, and if the constructor gets a nametype OID of
GSS_C_NT_EXPORT_NAME, then the resulting GSSName object contains only one
GSSMechName object inside it. But such a GSSMechname class then goes into
the SPI realm that is a different document.

FYI, the GSSName class might need a isMN() method that return true if it
is an MN and has only one element inside it. 

> 5) Very minor: it isn't obvious to me why there are 
> two versions of equals() in Jack's GSSName. One of them
> takes a GSSName parameter and the other takes an
> Object and throws an exception if the two can't 
> be compared. I imagine there's some reason for this, 
> but it would be useful to have that stated. 

The one that takes Object as parameter overrides the equals() method
inherited from the Object class to make it work correctly for GSSName. The
one that takes GSSName as parameter is the obvious one which all
programmers will gravitate to.

---

==========================================================================
This message was posted through the Stanford campus mailing list
server.  If you wish to unsubscribe from this mailing list, send the
message body of "unsubscribe ietf-cat-wg" to [email-masked]

---

From: "Jack Kabat" <[email-masked]>
Date: Tue, 6 Apr 1999 16:13:14 -0700

Hello Michael,

My comments to the issues you raise are listed below. These add to the
comments already sent by Mayank.

Regards,

Jack

>-----Original Message-----
>
>I've been going over Jack Kabat's Internet-Draft
>and comparing it with the prototype Java binding
>we did here in my atelier. (For Javadoc and some
>observations, see <http://www.panix.com/~jlefevre/GSS>).
>Modulo the interface/concrete class issue (I did
>interfaces, Jack did classes), there is a strong
>family resemblance between the two. There are some
>areas of divergence which seem to me to raise some
>interesting, if minor, technical issues:
>
>Our approach, on the other hand, is to have the
>per-message calls create and return an instance of
>a thing with the (admittedly unwieldy) name of
>GSSPerMessageCallResult, which has members with the
>actual QOP, privacy, token flags etc., as well as
>major and minor status and the actual output of the
>function (wrapped or unwrapped data, MIC, etc.).
>Our per-message calls take requested QOP and
>privacy as direct parameters (rather than as
>preset elements of the MessageProp object, as in
>Jack's scheme).
>
>It seems to me that our approach has the advantage of
>being simpler for the application programmer.
>

There is very little difference in both approaches. The MessageProp object
is just a data container. One possibility is for wrap to take QOP and
confidentiality as parameters and return messageProg:
public Messageprop Wrap(byte inbuf[], int offset, int len, Bool conf, int
qop);

All the application programmer has to do is to create an object with the
appropriate values new MessageProp(1, true). I don't think this is a big
complication.

>"exceptional"; hence the distinction. (Also, of

Example? GSS specification returns only errors or success. A handful of
context calls also return informatory values. We followed the traditional
Java approach and used exceptions to signal errors. We also indicate
informatory values through the usage of MessageProp in the per-message
calls. This covers all the error reporting modes specified in RFC 2078 so I
don't see any reason to include other return values. Did you have specific
examples in mind that we are not capturing?

>gets a "name for mechanism" and still retains
>the non-mechanism-specific name is to call
>clone() on a non-mech-specific name, and then
>canonicalize() on the clone.
>
>This seems a little roundabout to us; also, of
>course, it seems that objects with different
>sets of methods ought to be in different classes.

On the other hand, you probably would not want to create a new class because
of one new method? We tried having exactly what you suggest in our
prototype, but found it an over kill for this one difference. Also several
issues arose from having a constructor that may need to create one or the
other object (MN or generic name) based on the parameter passed in. Which
one would you return? Some implementations may also want to differ the
creation of the name until they are actually used (i.e. if I specify generic
name information in the constructor, I may not be able to create a MN at
that point, but once that name is passed into a call in which the mechanism
can be determined, then the underlying implementation can create the MN).

>
>4) GSS has two methods for adding mechanisms to
>credentials: add and add-in-place. Add creates a
>new credential with the added mechanism included;
>add in place doesn't create the new credential, but
>just folds the new mechanism into the existing
>credential. We replicated this arrangement in our
>implementation; our GSSCredential interface defines
>a method addCredential(), which returns a new instance
>of GSSCredential, and another method
>addCredentialInPlace(), which returns void and operates
>on the existing credential. Jack's approach, in
>effect, has only the add-in-place version; if you
>want a new credential, you add in place and then
>clone(), or vice-versa.

Again, I don't see this as a problem but a feature :-)
Clone is a standard Java method used to create a duplicate of an object.
This is something that Java programmers would be used to and expect to have
in a class. Unfortunately, there is no equivalent of this in C.

>6) Also minor: there's a method of GSSName called
>isAnonymous(), which doesn't, as far as I can see,
>correspond to anything in the GSS spec. What's this
>for?

GSS treats anonymous name with special behavior (see gss_compare_name). We
thought it would be useful to allow callers to determine a name of this
type. Gss_accept_sec_context returns the target name as one of its
parameters. This name may be anonymous. This methods provides an easy way of
determining this.

>
>7) Similar to above: there's a method, getDefaultMech,
>returning a mechoid, in GSSManager. Again this doesn't
>seem to correspond to anything in GSS, as far as I can
>see.
>
>8) Jack has a GSS-specific Channel Binding class and
>we don't; but I think this is a good idea and ought to
>be there.
>
>9) Similarly, his Oid class is richer in functionality
>than ours, in ways that I think make good sense.
>
>10) As the result of an extended discussion some months
>ago, Jack's and my specifications both contain versions
>of the per-message and token-establishment calls that use
>input and output streams rather than byte arrays for the
>tokens. This technique was originally devised as another
>way around the lack of output parameters in Java, but
>I'd like to hear some feedback from other people:
>is this a good idea, or not? If memory serves, Jack
>and I agreed in correspondence that the calls which take
>streams as parameters should not block on reading or
>writing these streams; this implies (inter alia) that the
>caller needs to ensure that at least an entire token is
>present in the input stream before calling the method.

The streams are controlled by the caller. The caller is free to decide the
appropriate behavior of the stream he/she chose to use. I don't think we
should specify the behavior of these objects in this specification. It is
entirely up to the caller to what he/she wishes to use. One of my reasons
for adding stream support, is that usage of an object instead of primitive
(byte array) gives the caller much more flexibility and control. I think of
a stream as an object managing some kind of data storage. This can be
anything from a socket, memory array, file, to an encoder which encodes the
written bytes into application specific format, before storing them.

>(And what does the method do if there isn't a complete
>token on the input stream, or it can't write the output
>stream -- rewind it and/or throw an exception? If the
>latter, with what major status? If not, with what output?)
>
>I wonder if this  "feature" isn't more trouble
>than it's worth, although Jack did convince me that it
>was kind of cool when we were exchanging e-mails about
>it.
>
>