Subject: GSS and IDUP

From: Graham Bland <[email-masked]>
Date: Wed, 14 Jan 1998 14:12:58 +0000

Firstly apology on two counts.
The timing of these comments is poor following last call, however at that 
time I had no comments.

Secondly the length, this is a collection of comments and issues rather than 
sending each as a seperate email I have collated them together.

The background from most of these has come from looking at an environment 
which will support both GSS and GSS-IDUP.  All are based on the latest 
documents.

IDUP_Get_token_details
 ------------------------------------
When Data encapsulation has been requested the application must pass 
sufficient data from the start of the P_IDU to include the token to the 
call.  The application has no way of determining how much data this is.  A 
return code of IDUP_S_MORE_PIDU_NEEDED should be allowed to enable the 
application to pass more data to the call.
The other option would be to require a minimum data size of for example 4kb 
or the entire token to be passed.  This would constrain the mechanism 
implementors to include  all the required data within the first 4kb of a 
token.

The call returns the idu_size, however where data encapsulation and multiple 
buffers are used a mechanism cannot determine this from the start of the 
P_IDU as the mechanism does not know the IDU length until the IDU has been 
fully processed (see later comment on IDU Length on multi buffer calls) as 
indicated by the end protect call by which time the token at the start of 
the P_IDU has already been emitted and cannot be changed.
Suggested behaviour here would be to return UNKNOWN as the idu_size with a 
status of GSS_S_COMPLETE for encapsulated data.

IDUP Multibuffer processing
 --------------------------------
While examining some of the SE Start/Process/End sequences of calls We have 
noted the following;

A mechanism (directly or indirectly via the environment) will need to 
preserve state information from one call to the next in a sequence of 
(SE/EV/GP) Start/Process/End calls.  This state information will almost 
certainly involve dynamic memory allocation.  If for some reason (e.g. an 
I/O error or user abort) an application calls a Start followed by zero or 
more Process calls but fails to call End, that memory will not be released 
in the normal way (i.e. on the End call).

Currently we have assumed, that, for a single instance of an environment, it 
is only valid to be performing a single multi-step operation at one time 
(e.g. a sequence such as SEStart, EVStart, SEProcess, EVProcess, SEEnd, 
EVEnd is not allowed). We have further specified that an environment should 
only be used in the thread that created it.

As a mechanism implementation detail, under the current scheme, it should be 
noted that if a mechanism receives a request to start any operation while a 
previous operation is still in progress, it should cancel the previous 
operation, releasing its state storage.  It should also release state 
storage when the environment is abolished.  Note however that this may mean 
that the state information may remain for some significant time after an 
operation fails or is cancelled at the application level.

At a specification level, it may be appropriate to suggest a 'cancel' 
function for each of the multi-step operations (for example 
IDUP_SE_MultiBuffer_Cancel), which would allow the application to indicate 
to IDUP that it was unable to make the additional Process calls due to some 
application level difficulty.

A further point is the possibility of including an 'operation' handle within 
the multi-step calls (i.e. an handle that is returned from the Start 
operation and must be passed to each subsequent matching process/end or 
cancel call).  This would allow state information to be associated with a 
series of calls and not bound to the environment.  This would remove the 
sequence and thread restrictions above.  At the moment any 
multi-thread/fibre application will have to establish an environment for 
each operation it will perform (and this may be expensive).  An alternative 
would be to provide a 'duplicate environment' function which should be able 
to avoid some aspects of environment establishment (e.g. certificate 
validation) and thus be less expensive that establishing a new environment.

On a side note, I dislike this start/process/end method of performing an 
operation over a large data source. The application developer has to include 
complex loops of calls, IDUP and the mechanism have to preserve state across 
calls, including the fact the buffer may terminate in the middle of some 
atomic unit of data at the token level (e.g. in the middle of an integer or 
OID) making restarting complex.  A far better solution would be to allow 
language specific bindings (where supported) to pass 'get more data' and 
'put more data' functions (or abstract base class) into the API, then at any 
point that the mechanism required more data, it simply calls back to 
retrieve that data.  This method also reduces the number of times data is 
copied from one buffer to another, as, for example,  these functions could 
just be file system i/o functions where the data resides on disk.  The 
start/process/end method was used extensively under Windows 3.1, as to 
prevent the system freezing during a lengthy operation the application had 
to invoke the message pump frequently.  The call-back method still allows 
this, but may require more stack space.

IDUP_ev_singlebuffer_verify
 ------------------------------------------
The idu_buffer is described in the API spec as an input and an output, in 
the “C” bindings this is implemented as two parameters one input buffer and 
one output buffer.  Both however have the same name of idu_buffer.  I 
suggest renaming these to external_idu_buffer for the input buffer and 
encapsulated_idu_buffer for the output.

IDUP_establish_env
 ------------------------------
The ret_services parameter is defined as a gss_OID_set, I believe this 
should be a gss_OID_set * to be consistent with the rest of the IDUP and GSS 
calls. While it is technically possible to pass the OID set by value (since 
it is a pointer) and for IDUP to add elements to a previously allocated set 
(via the application calling gss_create_empty_oid_set), everywhere else the 
allocation of the empty OID set is the responsibility of GSS/IDUP and it 
returns this by double pointer.

Status Codes
 --------------------
The GSS C-Bindings introduced two new status codes, defining error status 
codes up to 18 (GSS_NAME_NOT_MN), however the May 97 IDUP C-Bindings starts 
the IDUP extended error status codes from 17 (IDUP_S_BAD_TARG_INFO).  Thus 
error codes 17 and 18 are defined in both GSS and IDUP as different status 
returns.
I propose as change to IDUP C-bindings whereby the IDUP return codes start 
at 255 and work down to avoid conflicts with GSS

Credential Usage Type
 -----------------------------------
GSS C-Bindings Defines credential usage as an INT.  Latest IDUP draft 
defines it as a BIT-STRING.
The spec states "The calls given in Section 2.1 of GSS-API (including all 
associated parameters) are unchanged, although the interpretation of the 
cred_usage parameter in the GSS_API calls for IDUP purposes is as follows. 
..."
However the determination of the usage of the credential (i.e. for GSS usage 
 - context establishment, or for IDUP usage - environment establishment) 
does not occur until later - possibly after credential elements have been 
instantiated.
While it is possible to overload the use of the parameter, it would ease 
matters if the parameter was defined as a bit string in both cases.  For 
example

GSS_C_INITIATE                          1
GSS_C_ACCEPT                           2
IDUP_C_ENCRYPT_ONLY        8
IDUP_C_DECRYPT_ONLY      16
IDUP_C_SIGN_ONLY                32
IDUP_C_VERIFY_ONLY           64

GSS_C_BOTH                              (GSS_C_INITIATE | GSS_C_ACCEPT)
IDUP_C_NO_RESTRICTION  (IDUP_C_ENCRYPT_ONLY  |          
                                         IDUP_C_DECRYPT_ONLY  | 
 IDP_C_SIGN_ONLY  |
                                                              
 IDUP_C_VERIFY_ONLY)

 it is unclear as to what is intended in an environment with a mechanism 
which implements both GSS and IDUP.

This is proposed as a change to both IDUP and GSS C-bindings.

Parameter Types
 --------------------------
A number of GSS and GSS/IDUP structures define ordinality or size, below is 
a table summarising them.
Struct                                                                 field 
                     type
=====                                                              ==== 
                    ====
gss_buffer_t                                                  length 
                   size_t
gss_OID                                                         length 
                   OM_uint32
gss_OID_set                                                 count 
                    size_t
IDUP_Target_Info                                       bad_count 
          int
IDUP_Services_To_Perform                  no_of_services  OM_uint32
IDUP_Services_To_Receive no_of_services  OM_uint32
IDUP_Service_Descriptor_Set              count                       int
IDUP_Mechanism_Descriptor_Set      count                       int
idup_name_set                                            count 
                     int

As you can see, they lack consistency.  Over time it appears that the GSS 
C-Bindings have shifted from int to size_t for some items (e.g. 
gss_OID_set.count) - in particular the IDUP C-Bindings still refer to the 
old 'int' usage for GSS.

For consistency both IDUP should adopt size_t for count fields and OM_uint32 
for length fields.

Case usage
 ------------------
The GSS “C” bindings specifies function calls and structure members as lower 
case names, for consistency the IDUP “C” bindings should follow suit.

Idup_name_set
 -----------------------
idup_name_set is defined as:
typedef struct idup_name_set_desc_struct {
     int       count ;
     gss_name_t     elements ;
} idup_name_set_desc, *idup_name_set;
Where gss_name_t is an implementation defined type.

This definition does not work for all definitions of gss_name_t.  In 
particular it will not work for any which are either not pointer types or 
where the sizeof() operator does not evaluate to a constant.  For binary 
compatibility only, GSS  imposes the restriction that it should be a pointer 
type (Section B.4) and discourages, but does not preclude the use of void*. 
 For source compatibility, GSS does not impose any restriction on the 
implementation of gss_name_t.

With a rather simplistic view of the implementation of gss_name_t (e.g. 
precluding opaque types, non-pointers, void *, derived classes and 
extensible structures), the above would work.  However I don't believe that 
this restriction is intentional, nor acceptable.

In our case gss_name_t is defined as a pointer to an opaque type and thus 
you cannot apply the sizeof() operator to it.  In particular, expressions 
such as elements[1] cannot correctly be evaluated since the 
sizeof(elements[0]) would depend on the actual implementation the type. 
 Additionally we cannot expose the implementation as it is C++ specific and 
would not compile in C.

We have thus re-defined idup_name_set as;
typedef struct idup_name_set_desc_struct {
     int       count ;
     gss_name_t*    elements ;
} idup_name_set_desc, *idup_name_set;

This should not have a significant impact on source level compatibility, 
since most of the manipulation of name sets is via API functions 
(idup_add_name_set_member etc.).
Another choice would be to implement gss_name_t as a double pointer, but 
this would impose an, otherwise unnecessary, overhead in development, 
execution, and maintenance.

idup_acquire_cred_with_auth
 -------------------------------------------
We have defined idup_acquire_cred_with_auth as follows;
OM_uint32 GSS_ENTRY idup_acquire_cred_with_auth(
   gss_name_t               desired_name,
   gss_buffer_t             authenticator,
   OM_uint32                  time_req,
   gss_OID_set              desired_mechs,
   gss_cred_usage_t           cred_usage,
   OM_uint32*                 minor_status,
   gss_cred_id_t*             output_cred_handle,
   gss_OID_set*               actual_mechs,
   OM_uint32*                 time_rec) ;

This differs from the last C-Bindings where cred_usage is defined as 
gss_buffer_t and actual_mechs is defined as gss_OID_set.

It makes no sense whatsoever for cred_usage to be a gss_buffer_t, since 
functions like inquire_cred return gss_cred_usage_t.  I can only assume that 
this is some oddity from the fact that the parameter definition was noted as 
changing from INT to BITSTRING in the language independent API - however we 
have assumed that the intention here is to re-use the INT with bitmasks.

Actual_mechs is another place where there appears to be a wrong (or at least 
inconsistent) level of pointer.

Appendix IDUP-GSS-API example
 ---------------------------------------------------
Would it not make sense to include the GSS header file rather than replicate 
all the information.

Error codes - IDUP_C_ROUTINE_ERROR_OFFSET is not defined, how does this 
differ from GSS_C_ROUTINE_ERROR_OFFSET or is it the same.

The struct definition for IDUP_Prot_Service_desc, last parameter is missing 
a space between int and service_verification_info_id

IDU Length on multi buffer calls
 ---------------------------------------------
The IDUP calls IDUP_SE_MultiBuffer_StartProtect, 
IDUP_EV_MultiBuffer_Generate (with include_data_in_token TRUE) and 
IDUP_Protect all create a PIDU which contains an encapsulated IDU.

The total length of the IDU is not available at any point prior to the 
matching IDUP_xxxEndxxx call.

Thus the beginning of the PIDU cannot contain the length of the IDU (or 
related length) without the mechanism buffering the entire IDU.  This may be 
impractical due to the potential size of the IDU.

IDUP mechanisms are therefore constrained to use either
 - chaining (where the data is broken into blocks and the length of each 
block prefixes the block and the last block is marked - this requires 
buffering up to one block length or more at the receiver), or,
 - an 'end of data' marker (this marker must be guarantee never to occur in 
either the IDU or encrypted IDU - this requires buffering up to the length 
of the EOD marker at the receiver).

To resolve this issue, and allow mechanisms to store the size of the IDU at 
the start of the PIDU, the three calls listed above should have an 
additional parameter 'idu_size' which is required when encapsulation is 
required.
The idu_size should have a value 'UNKNOWN' (for example where encapsulating 
data from a pipe, or compressing on the fly) - some mechanisms may not 
support encapsulation if this value is UNKNOWN.

Is it possible or desirable for mechanisms to implement a restriction 
whereby encapsulation is not provided on the multi-buffer calls unless they 
naturally use one of the above solutions (chaining or EOD).

Return Codes
 --------------------
I suggest that an additional return code be added both to GSS and IDUP 
specifications to cover a case of inconsistent parameters, for example in 
idup_start_unprotect where only one of single_idu_buffer and 
final_pidu_buffer may have a zero length and the caller has passed both. 
Currently GSS_S_FAILURE must be returned which is not particularly 
informative to the application developer.

Idup_establish_env
 -----------------------------
Passing GSS_C_NO_OID_SET as the req_services parameter to idup_establish_env 
should be defined as requesting the full set of available services for that 
mechanism.

There is no point in establishing an environment with no services (hence 
GSS_C_NO_OID_SET is not really a valid input parameter), and given that the 
services are mechanism specific and may grow over time, there is no way for 
an application to discover which services are available without 
pre-knowledge (OK - how it then uses these services is another matter...). 
 It also simplifies the application developers job as they do not have to 
create an OID set to start with.

Credentials and Usage
 ----------------------------------
1.
The GSS C Bindings define 'cred_usage' as input only for both 
gss_acquire_cred and gss_add_cred. It does not comment on what should happen 
if only a subset of the usage is available (e.g, if BOTH is requested and 
only INITIATE is available, should that generate a GSS_C_NO_CRED?).

2.
The language API Specification (rfc2078bis-01) state that for 
gss_acquire_cred, that it should fail if the requested usage is not 
available, but gss_add_cred has an additional output parameter (with the 
same name as an input parameter) which suggests that add cred should return 
the set of usage”s available and succeed if any requested usage was 
available.  I say 'suggests' since the interpretation depends entirely on 
which 'cred_usage' the paragraph is referring to (i.e. the input or output).

The reason that I question this is that in the case of gss_acquire_cred, 
this would mean that the application programmer would basically have to 
acquire separate credentials for each operation type, since they could not 
be guaranteed that any combination would succeed (without making 
installation specific assumptions) and they would thus have to perform an 
exhaustive call search to find the best available.  Note that this is 
compounded by IDUPs 4 additional 'cred_usage' values.

For the above reason I believe that we should take the approach used by GSS 
everywhere else - i.e. request a set of features, but the onus is on 
application programmer to ensure that a sufficient subset was provided. 
 Thus, both acquire_cred and add_cred should have 'actual_cred_usage' output 
parameters.  The latter is a change to the c-bindings only, bringing it in 
line with the GSS spec, the former deviates from both.  However without some 
sort of resolution in this area, any application that wishes use GSS and 
IDUP would have to maintain separate credentials for each, negating much of 
 the value of a core set of credential management functions.

Note that I am currently making the assumption that in a multi-mechanism 
environment, credential acquisition succeeds if any combination of 
mechanisms satisfies the cred_usage.

3.
For credential acquisition within IDUP, you are allowed to define a 
restricted use for the credential (e.g. ENCRYPT_ONLY, DECRYPT_ONLY, 
SIGN_ONLY, VERIFY_ONLY and combinations thereof).
Additionally, when establishing the environment you can request an OID set 
of services to request (e.g PER_CONF, REC_CONF, PER_POO, REC_POO, ... and 
combinations thereof).
Can you see any value in having both?  Any of the IDUP 'cred_usage' bits 
appears to indicate that we require an IDUP credential element and thus I 
see no reason why service requirements are duplicated at both levels.  Can 
we suggest that the credential usage should therefore be IDUP_C_ENVIRONMENT 
(in addition to GSS_C_INITIATE and GSS_C_ACCEPT) and that restricted service 
requirements are only made at the environment establishment phase.  This is 
more in line with the GSS model  - as per the service flags (deleg_req_flag, 
mutual_req_flag, ...) given at gss_init_sec_context call.

This does not negate the previous comments, but would rather simplify the 
credential usage concept - i.e. a credential can be used for initiating 
contexts, accepting contexts or creating environments or combinations 
thereof (all lying in the same dimension).  The application programmer 
should request the desired features and check to see if the required subset 
is available.

Graham Bland
Zergo

--
Zergo Limited, The Square, Basing View, Basingstoke, Hants. RG21 4EG, UK
Tel: + 44 (0) 1442 342 600    Fax: +44 (0) 1256 812 901
Website:  http://www.zergo.com

---

From: Carlisle Adams <[email-masked]>
Date: Wed, 21 Jan 1998 14:19:15 -0500

Hi Graham,

>----------
>From: 	Graham Bland[SMTP:[email-masked]]
>Sent: 	Wednesday, January 14, 1998 9:12 AM
>To: 	[email-masked]
>Subject: 	GSS and IDUP
>

Thank you for the detailed comments and for your interest in an
environment that supports GSS and IDUP together.

I hope to issue a revised IDUP draft over the next few weeks (taking
into account input from various conversations at the Washington IETF
meeting in December).  At that time I will respond to, and incorporate,
your comments as best I can.  If you don't mind just being patient for a
couple of weeks while I finish up some other work, I would really
appreciate it...

Thanks again!

--------------------------------------------
Carlisle Adams
Entrust Technologies
[email-masked]
--------------------------------------------