xref: /freebsd/crypto/krb5/doc/appdev/gssapi.rst (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1Developing with GSSAPI
2======================
3
4The GSSAPI (Generic Security Services API) allows applications to
5communicate securely using Kerberos 5 or other security mechanisms.
6We recommend using the GSSAPI (or a higher-level framework which
7encompasses GSSAPI, such as SASL) for secure network communication
8over using the libkrb5 API directly.
9
10GSSAPIv2 is specified in :rfc:`2743` and :rfc:`2744`.  Also see
11:rfc:`7546` for a description of how to use the GSSAPI in a client or
12server program.
13
14This documentation will describe how various ways of using the
15GSSAPI will behave with the krb5 mechanism as implemented in MIT krb5,
16as well as krb5-specific extensions to the GSSAPI.
17
18
19Name types
20----------
21
22A GSSAPI application can name a local or remote entity by calling
23gss_import_name_, specifying a name type and a value.  The following
24name types are supported by the krb5 mechanism:
25
26* **GSS_C_NT_HOSTBASED_SERVICE**: The value should be a string of the
27  form ``service`` or ``service@hostname``.  This is the most common
28  way to name target services when initiating a security context, and
29  is the most likely name type to work across multiple mechanisms.
30
31* **GSS_KRB5_NT_PRINCIPAL_NAME**: The value should be a principal name
32  string.  This name type only works with the krb5 mechanism, and is
33  defined in the ``<gssapi/gssapi_krb5.h>`` header.
34
35* **GSS_C_NT_USER_NAME** or **GSS_C_NULL_OID**: The value is treated
36  as an unparsed principal name string, as above.  These name types
37  may work with mechanisms other than krb5, but will have different
38  interpretations in those mechanisms.  **GSS_C_NT_USER_NAME** is
39  intended to be used with a local username, which will parse into a
40  single-component principal in the default realm.
41
42* **GSS_C_NT_ANONYMOUS**: The value is ignored.  The anonymous
43  principal is used, allowing a client to authenticate to a server
44  without asserting a particular identity (which may or may not be
45  allowed by a particular server or Kerberos realm).
46
47* **GSS_C_NT_MACHINE_UID_NAME**: The value is uid_t object.  On
48  Unix-like systems, the username of the uid is looked up in the
49  system user database and the resulting username is parsed as a
50  principal name.
51
52* **GSS_C_NT_STRING_UID_NAME**: As above, but the value is a decimal
53  string representation of the uid.
54
55* **GSS_C_NT_EXPORT_NAME**: The value must be the result of a
56  gss_export_name_ call.
57
58* **GSS_KRB5_NT_ENTERPRISE_NAME**: The value should be a krb5
59  enterprise name string (see :rfc:`6806` section 5), in the form
60  ``user@suffix``.  This name type is used to convey alias names, and
61  is defined in the ``<gssapi/gssapi_krb5.h>`` header.  (New in
62  release 1.17.)
63
64* **GSS_KRB5_NT_X509_CERT**: The value should be an X.509 certificate
65  encoded according to :rfc:`5280`.  This name form can be used for
66  the desired_name parameter of gss_acquire_cred_impersonate_name(),
67  to identify the S4U2Self user by certificate.  (New in release
68  1.19.)
69
70
71Initiator credentials
72---------------------
73
74A GSSAPI client application uses gss_init_sec_context_ to establish a
75security context.  The *initiator_cred_handle* parameter determines
76what tickets are used to establish the connection.  An application can
77either pass **GSS_C_NO_CREDENTIAL** to use the default client
78credential, or it can use gss_acquire_cred_ beforehand to acquire an
79initiator credential.  The call to gss_acquire_cred_ may include a
80*desired_name* parameter, or it may pass **GSS_C_NO_NAME** if it does
81not have a specific name preference.
82
83If the desired name for a krb5 initiator credential is a host-based
84name, it is converted to a principal name of the form
85``service/hostname`` in the local realm, where *hostname* is the local
86hostname if not specified.  The hostname will be canonicalized using
87forward name resolution, and possibly also using reverse name
88resolution depending on the value of the **rdns** variable in
89:ref:`libdefaults`.
90
91If a desired name is specified in the call to gss_acquire_cred_, the
92krb5 mechanism will attempt to find existing tickets for that client
93principal name in the default credential cache or collection.  If the
94default cache type does not support a collection, and the default
95cache contains credentials for a different principal than the desired
96name, a **GSS_S_CRED_UNAVAIL** error will be returned with a minor
97code indicating a mismatch.
98
99If no existing tickets are available for the desired name, but the
100name has an entry in the default client :ref:`keytab_definition`, the
101krb5 mechanism will acquire initial tickets for the name using the
102default client keytab.
103
104If no desired name is specified, credential acquisition will be
105deferred until the credential is used in a call to
106gss_init_sec_context_ or gss_inquire_cred_.  If the call is to
107gss_init_sec_context_, the target name will be used to choose a client
108principal name using the credential cache selection facility.  (This
109facility might, for instance, try to choose existing tickets for a
110client principal in the same realm as the target service).  If there
111are no existing tickets for the chosen principal, but it is present in
112the default client keytab, the krb5 mechanism will acquire initial
113tickets using the keytab.
114
115If the target name cannot be used to select a client principal
116(because the credentials are used in a call to gss_inquire_cred_), or
117if the credential cache selection facility cannot choose a principal
118for it, the default credential cache will be selected if it exists and
119contains tickets.
120
121If the default credential cache does not exist, but the default client
122keytab does, the krb5 mechanism will try to acquire initial tickets
123for the first principal in the default client keytab.
124
125If the krb5 mechanism acquires initial tickets using the default
126client keytab, the resulting tickets will be stored in the default
127cache or collection, and will be refreshed by future calls to
128gss_acquire_cred_ as they approach their expire time.
129
130
131Acceptor names
132--------------
133
134A GSSAPI server application uses gss_accept_sec_context_ to establish
135a security context based on tokens provided by the client.  The
136*acceptor_cred_handle* parameter determines what
137:ref:`keytab_definition` entries may be authenticated to by the
138client, if the krb5 mechanism is used.
139
140The simplest choice is to pass **GSS_C_NO_CREDENTIAL** as the acceptor
141credential.  In this case, clients may authenticate to any service
142principal in the default keytab (typically |keytab|, or the value of
143the **KRB5_KTNAME** environment variable).  This is the recommended
144approach if the server application has no specific requirements to the
145contrary.
146
147A server may acquire an acceptor credential with gss_acquire_cred_ and
148a *cred_usage* of **GSS_C_ACCEPT** or **GSS_C_BOTH**.  If the
149*desired_name* parameter is **GSS_C_NO_NAME**, then clients will be
150allowed to authenticate to any service principal in the default
151keytab, just as if no acceptor credential was supplied.
152
153If a server wishes to specify a *desired_name* to gss_acquire_cred_,
154the most common choice is a host-based name.  If the host-based
155*desired_name* contains just a *service*, then clients will be allowed
156to authenticate to any host-based service principal (that is, a
157principal of the form ``service/hostname@REALM``) for the named
158service, regardless of hostname or realm, as long as it is present in
159the default keytab.  If the input name contains both a *service* and a
160*hostname*, clients will be allowed to authenticate to any host-based
161principal for the named service and hostname, regardless of realm.
162
163.. note::
164
165          If a *hostname* is specified, it will be canonicalized
166          using forward name resolution, and possibly also using
167          reverse name resolution depending on the value of the
168          **rdns** variable in :ref:`libdefaults`.
169
170.. note::
171
172          If the **ignore_acceptor_hostname** variable in
173          :ref:`libdefaults` is enabled, then *hostname* will be
174          ignored even if one is specified in the input name.
175
176.. note::
177
178          In MIT krb5 versions prior to 1.10, and in Heimdal's
179          implementation of the krb5 mechanism, an input name with
180          just a *service* is treated like an input name of
181          ``service@localhostname``, where *localhostname* is the
182          string returned by gethostname().
183
184If the *desired_name* is a krb5 principal name or a local system name
185type which is mapped to a krb5 principal name, clients will only be
186allowed to authenticate to that principal in the default keytab.
187
188
189Name Attributes
190---------------
191
192In release 1.8 or later, the gss_inquire_name_ and
193gss_get_name_attribute_ functions, specified in :rfc:`6680`, can be
194used to retrieve name attributes from the *src_name* returned by
195gss_accept_sec_context_.  The following attributes are defined when
196the krb5 mechanism is used:
197
198.. _gssapi_authind_attr:
199
200* "auth-indicators" attribute:
201
202This attribute will be included in the gss_inquire_name_ output if the
203ticket contains :ref:`authentication indicators <auth_indicator>`.
204One indicator is returned per invocation of gss_get_name_attribute_,
205so multiple invocations may be necessary to retrieve all of the
206indicators from the ticket.  (New in release 1.15.)
207
208
209Credential store extensions
210---------------------------
211
212Beginning with release 1.11, the following GSSAPI extensions declared
213in ``<gssapi/gssapi_ext.h>`` can be used to specify how credentials
214are acquired or stored::
215
216    struct gss_key_value_element_struct {
217        const char *key;
218        const char *value;
219    };
220    typedef struct gss_key_value_element_struct gss_key_value_element_desc;
221
222    struct gss_key_value_set_struct {
223        OM_uint32 count;
224        gss_key_value_element_desc *elements;
225    };
226    typedef const struct gss_key_value_set_struct gss_key_value_set_desc;
227    typedef const gss_key_value_set_desc *gss_const_key_value_set_t;
228
229    OM_uint32 gss_acquire_cred_from(OM_uint32 *minor_status,
230                                    const gss_name_t desired_name,
231                                    OM_uint32 time_req,
232                                    const gss_OID_set desired_mechs,
233                                    gss_cred_usage_t cred_usage,
234                                    gss_const_key_value_set_t cred_store,
235                                    gss_cred_id_t *output_cred_handle,
236                                    gss_OID_set *actual_mechs,
237                                    OM_uint32 *time_rec);
238
239    OM_uint32 gss_store_cred_into(OM_uint32 *minor_status,
240                                  gss_cred_id_t input_cred_handle,
241                                  gss_cred_usage_t cred_usage,
242                                  const gss_OID desired_mech,
243                                  OM_uint32 overwrite_cred,
244                                  OM_uint32 default_cred,
245                                  gss_const_key_value_set_t cred_store,
246                                  gss_OID_set *elements_stored,
247                                  gss_cred_usage_t *cred_usage_stored);
248
249The additional *cred_store* parameter allows the caller to specify
250information about how the credentials should be obtained and stored.
251The following options are supported by the krb5 mechanism:
252
253* **ccache**: For acquiring initiator credentials, the name of the
254  :ref:`credential cache <ccache_definition>` to which the handle will
255  refer.  For storing credentials, the name of the cache or collection
256  where the credentials will be stored (see below).
257
258* **client_keytab**: For acquiring initiator credentials, the name of
259  the :ref:`keytab <keytab_definition>` which will be used, if
260  necessary, to refresh the credentials in the cache.
261
262* **keytab**: For acquiring acceptor credentials, the name of the
263  :ref:`keytab <keytab_definition>` to which the handle will refer.
264  In release 1.19 and later, this option also determines the keytab to
265  be used for verification when initiator credentials are acquired
266  using a password and verified.
267
268* **password**: For acquiring initiator credentials, this option
269  instructs the mechanism to acquire fresh credentials into a unique
270  memory credential cache.  This option may not be used with the
271  **ccache** or **client_keytab** options, and a *desired_name* must
272  be specified.  (New in release 1.19.)
273
274* **rcache**: For acquiring acceptor credentials, the name of the
275  :ref:`replay cache <rcache_definition>` to be used when processing
276  the initiator tokens.  (New in release 1.13.)
277
278* **verify**: For acquiring initiator credentials, this option
279  instructs the mechanism to verify the credentials by obtaining a
280  ticket to a service with a known key.  The service key is obtained
281  from the keytab specified with the **keytab** option or the default
282  keytab.  The value may be the name of a principal in the keytab, or
283  the empty string.  If the empty string is given, any ``host``
284  service principal in the keytab may be used.  (New in release 1.19.)
285
286In release 1.20 or later, if a collection name is specified for
287**cache** in a call to gss_store_cred_into(), an existing cache for
288the client principal within the collection will be selected, or a new
289cache will be created within the collection.  If *overwrite_cred* is
290false and the selected credential cache already exists, a
291**GSS_S_DUPLICATE_ELEMENT** error will be returned.  If *default_cred*
292is true, the primary cache of the collection will be switched to the
293selected cache.
294
295
296Importing and exporting credentials
297-----------------------------------
298
299The following GSSAPI extensions can be used to import and export
300credentials (declared in ``<gssapi/gssapi_ext.h>``)::
301
302    OM_uint32 gss_export_cred(OM_uint32 *minor_status,
303                              gss_cred_id_t cred_handle,
304                              gss_buffer_t token);
305
306    OM_uint32 gss_import_cred(OM_uint32 *minor_status,
307                              gss_buffer_t token,
308                              gss_cred_id_t *cred_handle);
309
310The first function serializes a GSSAPI credential handle into a
311buffer; the second unseralizes a buffer into a GSSAPI credential
312handle.  Serializing a credential does not destroy it.  If any of the
313mechanisms used in *cred_handle* do not support serialization,
314gss_export_cred will return **GSS_S_UNAVAILABLE**.  As with other
315GSSAPI serialization functions, these extensions are only intended to
316work with a matching implementation on the other side; they do not
317serialize credentials in a standardized format.
318
319A serialized credential may contain secret information such as ticket
320session keys.  The serialization format does not protect this
321information from eavesdropping or tampering.  The calling application
322must take care to protect the serialized credential when communicating
323it over an insecure channel or to an untrusted party.
324
325A krb5 GSSAPI credential may contain references to a credential cache,
326a client keytab, an acceptor keytab, and a replay cache.  These
327resources are normally serialized as references to their external
328locations (such as the filename of the credential cache).  Because of
329this, a serialized krb5 credential can only be imported by a process
330with similar privileges to the exporter.  A serialized credential
331should not be trusted if it originates from a source with lower
332privileges than the importer, as it may contain references to external
333credential cache, keytab, or replay cache resources not accessible to
334the originator.
335
336An exception to the above rule applies when a krb5 GSSAPI credential
337refers to a memory credential cache, as is normally the case for
338delegated credentials received by gss_accept_sec_context_.  In this
339case, the contents of the credential cache are serialized, so that the
340resulting token may be imported even if the original memory credential
341cache no longer exists.
342
343
344Constrained delegation (S4U)
345----------------------------
346
347The Microsoft S4U2Self and S4U2Proxy Kerberos protocol extensions
348allow an intermediate service to acquire credentials from a client to
349a target service without requiring the client to delegate a
350ticket-granting ticket, if the KDC is configured to allow it.
351
352To perform a constrained delegation operation, the intermediate
353service must submit to the KDC an "evidence ticket" from the client to
354the intermediate service.  An evidence ticket can be acquired when the
355client authenticates to the intermediate service with Kerberos, or
356with an S4U2Self request if the KDC allows it.  The MIT krb5 GSSAPI
357library represents an evidence ticket using a "proxy credential",
358which is a special kind of gss_cred_id_t object whose underlying
359credential cache contains the evidence ticket and a krbtgt ticket for
360the intermediate service.
361
362To acquire a proxy credential during client authentication, the
363service should first create an acceptor credential using the
364**GSS_C_BOTH** usage.  The application should then pass this
365credential as the *acceptor_cred_handle* to gss_accept_sec_context_,
366and also pass a *delegated_cred_handle* output parameter to receive a
367proxy credential containing the evidence ticket.  The output value of
368*delegated_cred_handle* may be a delegated ticket-granting ticket if
369the client sent one, or a proxy credential if not.  If the library can
370determine that the client's ticket is not a valid evidence ticket, it
371will place **GSS_C_NO_CREDENTIAL** in *delegated_cred_handle*.
372
373To acquire a proxy credential using an S4U2Self request, the service
374can use the following GSSAPI extension::
375
376    OM_uint32 gss_acquire_cred_impersonate_name(OM_uint32 *minor_status,
377                                                gss_cred_id_t icred,
378                                                gss_name_t desired_name,
379                                                OM_uint32 time_req,
380                                                gss_OID_set desired_mechs,
381                                                gss_cred_usage_t cred_usage,
382                                                gss_cred_id_t *output_cred,
383                                                gss_OID_set *actual_mechs,
384                                                OM_uint32 *time_rec);
385
386The parameters to this function are similar to those of
387gss_acquire_cred_, except that *icred* is used to make an S4U2Self
388request to the KDC for a ticket from *desired_name* to the
389intermediate service.  Both *icred* and *desired_name* are required
390for this function; passing **GSS_C_NO_CREDENTIAL** or
391**GSS_C_NO_NAME** will cause the call to fail.  *icred* must contain a
392krbtgt ticket for the intermediate service.  The result of this
393operation is a proxy credential.  (Prior to release 1.18, the result
394of this operation may be a regular credential for *desired_name*, if
395the KDC issues a non-forwardable ticket.)
396
397Once the intermediate service has a proxy credential, it can simply
398pass it to gss_init_sec_context_ as the *initiator_cred_handle*
399parameter, and the desired service as the *target_name* parameter.
400The GSSAPI library will present the krbtgt ticket and evidence ticket
401in the proxy credential to the KDC in an S4U2Proxy request; if the
402intermediate service has the appropriate permissions, the KDC will
403issue a ticket from the client to the target service.  The GSSAPI
404library will then use this ticket to authenticate to the target
405service.
406
407If an application needs to find out whether a credential it holds is a
408proxy credential and the name of the intermediate service, it can
409query the credential with the **GSS_KRB5_GET_CRED_IMPERSONATOR** OID
410(new in release 1.16, declared in ``<gssapi/gssapi_krb5.h>``) using
411the gss_inquire_cred_by_oid extension (declared in
412``<gssapi/gssapi_ext.h>``)::
413
414    OM_uint32 gss_inquire_cred_by_oid(OM_uint32 *minor_status,
415                                      const gss_cred_id_t cred_handle,
416                                      gss_OID desired_object,
417                                      gss_buffer_set_t *data_set);
418
419If the call succeeds and *cred_handle* is a proxy credential,
420*data_set* will be set to a single-element buffer set containing the
421unparsed principal name of the intermediate service.  If *cred_handle*
422is not a proxy credential, *data_set* will be set to an empty buffer
423set.  If the library does not support the query,
424gss_inquire_cred_by_oid will return **GSS_S_UNAVAILABLE**.
425
426
427AEAD message wrapping
428---------------------
429
430The following GSSAPI extensions (declared in
431``<gssapi/gssapi_ext.h>``) can be used to wrap and unwrap messages
432with additional "associated data" which is integrity-checked but is
433not included in the output buffer::
434
435    OM_uint32 gss_wrap_aead(OM_uint32 *minor_status,
436                            gss_ctx_id_t context_handle,
437                            int conf_req_flag, gss_qop_t qop_req,
438                            gss_buffer_t input_assoc_buffer,
439                            gss_buffer_t input_payload_buffer,
440                            int *conf_state,
441                            gss_buffer_t output_message_buffer);
442
443    OM_uint32 gss_unwrap_aead(OM_uint32 *minor_status,
444                              gss_ctx_id_t context_handle,
445                              gss_buffer_t input_message_buffer,
446                              gss_buffer_t input_assoc_buffer,
447                              gss_buffer_t output_payload_buffer,
448                              int *conf_state,
449                              gss_qop_t *qop_state);
450
451Wrap tokens created with gss_wrap_aead will successfully unwrap only
452if the same *input_assoc_buffer* contents are presented to
453gss_unwrap_aead.
454
455
456IOV message wrapping
457--------------------
458
459The following extensions (declared in ``<gssapi/gssapi_ext.h>``) can
460be used for in-place encryption, fine-grained control over wrap token
461layout, and for constructing wrap tokens compatible with Microsoft DCE
462RPC::
463
464    typedef struct gss_iov_buffer_desc_struct {
465        OM_uint32 type;
466        gss_buffer_desc buffer;
467    } gss_iov_buffer_desc, *gss_iov_buffer_t;
468
469    OM_uint32 gss_wrap_iov(OM_uint32 *minor_status,
470                           gss_ctx_id_t context_handle,
471                           int conf_req_flag, gss_qop_t qop_req,
472                           int *conf_state,
473                           gss_iov_buffer_desc *iov, int iov_count);
474
475    OM_uint32 gss_unwrap_iov(OM_uint32 *minor_status,
476                             gss_ctx_id_t context_handle,
477                             int *conf_state, gss_qop_t *qop_state,
478                             gss_iov_buffer_desc *iov, int iov_count);
479
480    OM_uint32 gss_wrap_iov_length(OM_uint32 *minor_status,
481                                  gss_ctx_id_t context_handle,
482                                  int conf_req_flag,
483                                  gss_qop_t qop_req, int *conf_state,
484                                  gss_iov_buffer_desc *iov,
485                                  int iov_count);
486
487    OM_uint32 gss_release_iov_buffer(OM_uint32 *minor_status,
488                                     gss_iov_buffer_desc *iov,
489                                     int iov_count);
490
491The caller of gss_wrap_iov provides an array of gss_iov_buffer_desc
492structures, each containing a type and a gss_buffer_desc structure.
493Valid types include:
494
495* **GSS_C_BUFFER_TYPE_DATA**: A data buffer to be included in the
496  token, and to be encrypted or decrypted in-place if the token is
497  confidentiality-protected.
498
499* **GSS_C_BUFFER_TYPE_HEADER**: The GSSAPI wrap token header and
500  underlying cryptographic header.
501
502* **GSS_C_BUFFER_TYPE_TRAILER**: The cryptographic trailer, if one is
503  required.
504
505* **GSS_C_BUFFER_TYPE_PADDING**: Padding to be combined with the data
506  during encryption and decryption.  (The implementation may choose to
507  place padding in the trailer buffer, in which case it will set the
508  padding buffer length to 0.)
509
510* **GSS_C_BUFFER_TYPE_STREAM**: For unwrapping only, a buffer
511  containing a complete wrap token in standard format to be unwrapped.
512
513* **GSS_C_BUFFER_TYPE_SIGN_ONLY**: A buffer to be included in the
514  token's integrity protection checksum, but not to be encrypted or
515  included in the token itself.
516
517For gss_wrap_iov, the IOV list should contain one HEADER buffer,
518followed by zero or more SIGN_ONLY buffers, followed by one or more
519DATA buffers, followed by a TRAILER buffer.  The memory pointed to by
520the buffers is not required to be contiguous or in any particular
521order.  If *conf_req_flag* is true, DATA buffers will be encrypted
522in-place, while SIGN_ONLY buffers will not be modified.
523
524The type of an output buffer may be combined with
525**GSS_C_BUFFER_FLAG_ALLOCATE** to request that gss_wrap_iov allocate
526the buffer contents.  If gss_wrap_iov allocates a buffer, it sets the
527**GSS_C_BUFFER_FLAG_ALLOCATED** flag on the buffer type.
528gss_release_iov_buffer can be used to release all allocated buffers
529within an iov list and unset their allocated flags.  Here is an
530example of how gss_wrap_iov can be used with allocation requested
531(*ctx* is assumed to be a previously established gss_ctx_id_t)::
532
533    OM_uint32 major, minor;
534    gss_iov_buffer_desc iov[4];
535    char str[] = "message";
536
537    iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_FLAG_ALLOCATE;
538    iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
539    iov[1].buffer.value = str;
540    iov[1].buffer.length = strlen(str);
541    iov[2].type = GSS_IOV_BUFFER_TYPE_PADDING | GSS_IOV_BUFFER_FLAG_ALLOCATE;
542    iov[3].type = GSS_IOV_BUFFER_TYPE_TRAILER | GSS_IOV_BUFFER_FLAG_ALLOCATE;
543
544    major = gss_wrap_iov(&minor, ctx, 1, GSS_C_QOP_DEFAULT, NULL,
545                         iov, 4);
546    if (GSS_ERROR(major))
547        handle_error(major, minor);
548
549    /* Transmit or otherwise use resulting buffers. */
550
551    (void)gss_release_iov_buffer(&minor, iov, 4);
552
553If the caller does not choose to request buffer allocation by
554gss_wrap_iov, it should first call gss_wrap_iov_length to query the
555lengths of the HEADER, PADDING, and TRAILER buffers.  DATA buffers
556must be provided in the iov list so that padding length can be
557computed correctly, but the output buffers need not be initialized.
558Here is an example of using gss_wrap_iov_length and gss_wrap_iov::
559
560    OM_uint32 major, minor;
561    gss_iov_buffer_desc iov[4];
562    char str[1024] = "message", *ptr;
563
564    iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
565    iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
566    iov[1].buffer.value = str;
567    iov[1].buffer.length = strlen(str);
568
569    iov[2].type = GSS_IOV_BUFFER_TYPE_PADDING;
570    iov[3].type = GSS_IOV_BUFFER_TYPE_TRAILER;
571
572    major = gss_wrap_iov_length(&minor, ctx, 1, GSS_C_QOP_DEFAULT,
573                                NULL, iov, 4);
574    if (GSS_ERROR(major))
575        handle_error(major, minor);
576    if (strlen(str) + iov[0].buffer.length + iov[2].buffer.length +
577        iov[3].buffer.length > sizeof(str))
578        handle_out_of_space_error();
579    ptr = str + strlen(str);
580    iov[0].buffer.value = ptr;
581    ptr += iov[0].buffer.length;
582    iov[2].buffer.value = ptr;
583    ptr += iov[2].buffer.length;
584    iov[3].buffer.value = ptr;
585
586    major = gss_wrap_iov(&minor, ctx, 1, GSS_C_QOP_DEFAULT, NULL,
587                         iov, 4);
588    if (GSS_ERROR(major))
589        handle_error(major, minor);
590
591If the context was established using the **GSS_C_DCE_STYLE** flag
592(described in :rfc:`4757`), wrap tokens compatible with Microsoft DCE
593RPC can be constructed.  In this case, the IOV list must include a
594SIGN_ONLY buffer, a DATA buffer, a second SIGN_ONLY buffer, and a
595HEADER buffer in that order (the order of the buffer contents remains
596arbitrary).  The application must pad the DATA buffer to a multiple of
59716 bytes as no padding or trailer buffer is used.
598
599gss_unwrap_iov may be called with an IOV list just like one which
600would be provided to gss_wrap_iov.  DATA buffers will be decrypted
601in-place if they were encrypted, and SIGN_ONLY buffers will not be
602modified.
603
604Alternatively, gss_unwrap_iov may be called with a single STREAM
605buffer, zero or more SIGN_ONLY buffers, and a single DATA buffer.  The
606STREAM buffer is interpreted as a complete wrap token.  The STREAM
607buffer will be modified in-place to decrypt its contents.  The DATA
608buffer will be initialized to point to the decrypted data within the
609STREAM buffer, unless it has the **GSS_C_BUFFER_FLAG_ALLOCATE** flag
610set, in which case it will be initialized with a copy of the decrypted
611data.  Here is an example (*token* and *token_len* are assumed to be a
612pre-existing pointer and length for a modifiable region of data)::
613
614    OM_uint32 major, minor;
615    gss_iov_buffer_desc iov[2];
616
617    iov[0].type = GSS_IOV_BUFFER_TYPE_STREAM;
618    iov[0].buffer.value = token;
619    iov[0].buffer.length = token_len;
620    iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
621    major = gss_unwrap_iov(&minor, ctx, NULL, NULL, iov, 2);
622    if (GSS_ERROR(major))
623        handle_error(major, minor);
624
625    /* Decrypted data is in iov[1].buffer, pointing to a subregion of
626     * token. */
627
628.. _gssapi_mic_token:
629
630IOV MIC tokens
631--------------
632
633The following extensions (declared in ``<gssapi/gssapi_ext.h>``) can
634be used in release 1.12 or later to construct and verify MIC tokens
635using an IOV list::
636
637    OM_uint32 gss_get_mic_iov(OM_uint32 *minor_status,
638                              gss_ctx_id_t context_handle,
639                              gss_qop_t qop_req,
640                              gss_iov_buffer_desc *iov,
641                              int iov_count);
642
643    OM_uint32 gss_get_mic_iov_length(OM_uint32 *minor_status,
644                                     gss_ctx_id_t context_handle,
645                                     gss_qop_t qop_req,
646                                     gss_iov_buffer_desc *iov,
647                                     iov_count);
648
649    OM_uint32 gss_verify_mic_iov(OM_uint32 *minor_status,
650                                 gss_ctx_id_t context_handle,
651                                 gss_qop_t *qop_state,
652                                 gss_iov_buffer_desc *iov,
653                                 int iov_count);
654
655The caller of gss_get_mic_iov provides an array of gss_iov_buffer_desc
656structures, each containing a type and a gss_buffer_desc structure.
657Valid types include:
658
659* **GSS_C_BUFFER_TYPE_DATA** and **GSS_C_BUFFER_TYPE_SIGN_ONLY**: The
660  corresponding buffer for each of these types will be signed for the
661  MIC token, in the order provided.
662
663* **GSS_C_BUFFER_TYPE_MIC_TOKEN**: The GSSAPI MIC token.
664
665The type of the MIC_TOKEN buffer may be combined with
666**GSS_C_BUFFER_FLAG_ALLOCATE** to request that gss_get_mic_iov
667allocate the buffer contents.  If gss_get_mic_iov allocates the
668buffer, it sets the **GSS_C_BUFFER_FLAG_ALLOCATED** flag on the buffer
669type.  gss_release_iov_buffer can be used to release all allocated
670buffers within an iov list and unset their allocated flags.  Here is
671an example of how gss_get_mic_iov can be used with allocation
672requested (*ctx* is assumed to be a previously established
673gss_ctx_id_t)::
674
675    OM_uint32 major, minor;
676    gss_iov_buffer_desc iov[3];
677
678    iov[0].type = GSS_IOV_BUFFER_TYPE_DATA;
679    iov[0].buffer.value = "sign1";
680    iov[0].buffer.length = 5;
681    iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
682    iov[1].buffer.value = "sign2";
683    iov[1].buffer.length = 5;
684    iov[2].type = GSS_IOV_BUFFER_TYPE_MIC_TOKEN | GSS_IOV_BUFFER_FLAG_ALLOCATE;
685
686    major = gss_get_mic_iov(&minor, ctx, GSS_C_QOP_DEFAULT, iov, 3);
687    if (GSS_ERROR(major))
688        handle_error(major, minor);
689
690    /* Transmit or otherwise use iov[2].buffer. */
691
692    (void)gss_release_iov_buffer(&minor, iov, 3);
693
694If the caller does not choose to request buffer allocation by
695gss_get_mic_iov, it should first call gss_get_mic_iov_length to query
696the length of the MIC_TOKEN buffer.  Here is an example of using
697gss_get_mic_iov_length and gss_get_mic_iov::
698
699    OM_uint32 major, minor;
700    gss_iov_buffer_desc iov[2];
701    char data[1024];
702
703    iov[0].type = GSS_IOV_BUFFER_TYPE_MIC_TOKEN;
704    iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
705    iov[1].buffer.value = "message";
706    iov[1].buffer.length = 7;
707
708    major = gss_get_mic_iov_length(&minor, ctx, GSS_C_QOP_DEFAULT, iov, 2);
709    if (GSS_ERROR(major))
710        handle_error(major, minor);
711    if (iov[0].buffer.length > sizeof(data))
712        handle_out_of_space_error();
713    iov[0].buffer.value = data;
714
715    major = gss_get_mic_iov(&minor, ctx, GSS_C_QOP_DEFAULT, iov, 2);
716    if (GSS_ERROR(major))
717        handle_error(major, minor);
718
719
720.. _gss_accept_sec_context: https://tools.ietf.org/html/rfc2744.html#section-5.1
721.. _gss_acquire_cred: https://tools.ietf.org/html/rfc2744.html#section-5.2
722.. _gss_export_name: https://tools.ietf.org/html/rfc2744.html#section-5.13
723.. _gss_get_name_attribute: https://tools.ietf.org/html/6680.html#section-7.5
724.. _gss_import_name: https://tools.ietf.org/html/rfc2744.html#section-5.16
725.. _gss_init_sec_context: https://tools.ietf.org/html/rfc2744.html#section-5.19
726.. _gss_inquire_name: https://tools.ietf.org/html/rfc6680.txt#section-7.4
727.. _gss_inquire_cred: https://tools.ietf.org/html/rfc2744.html#section-5.21
728