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