]> git.ipfire.org Git - thirdparty/krb5.git/commitdiff
Add GSSAPI IOV MIC functions
authorGreg Hudson <ghudson@mit.edu>
Sun, 8 Sep 2013 01:13:48 +0000 (21:13 -0400)
committerGreg Hudson <ghudson@mit.edu>
Wed, 18 Sep 2013 22:22:16 +0000 (18:22 -0400)
Add gss_get_mic_iov, gss_get_mic_iov_length, and gss_verify_mic_iov
functions, which work similarly to the corresponding IOV wrap
functions.  Add a new buffer type GSS_IOV_BUFFER_TYPE_MIC_TOKEN for
the destination buffer.

Most of the internal code for this was already present, and just
needed to be fixed up and adjusted to use the new buffer type for the
MIC token.

ticket: 7705 (new)

16 files changed:
src/lib/gssapi/generic/gssapi_ext.h
src/lib/gssapi/krb5/gssapiP_krb5.h
src/lib/gssapi/krb5/gssapi_krb5.c
src/lib/gssapi/krb5/k5sealiov.c
src/lib/gssapi/krb5/k5sealv3iov.c
src/lib/gssapi/krb5/k5unsealiov.c
src/lib/gssapi/krb5/util_cksum.c
src/lib/gssapi/krb5/util_crypt.c
src/lib/gssapi/libgssapi_krb5.exports
src/lib/gssapi/mechglue/g_unwrap_iov.c
src/lib/gssapi/mechglue/g_wrap_iov.c
src/lib/gssapi/mechglue/mglueP.h
src/lib/gssapi/spnego/gssapiP_spnego.h
src/lib/gssapi/spnego/spnego_mech.c
src/lib/gssapi32.def
src/tests/gssapi/t_iov.c

index d8c8b6ab85e66a2923bc95220d069c29b115df61..9ad44216d05e97bce885acac91d52c1437e39eb2 100644 (file)
@@ -238,6 +238,7 @@ typedef struct gss_iov_buffer_desc_struct {
 #define GSS_IOV_BUFFER_TYPE_PADDING        9   /* Padding */
 #define GSS_IOV_BUFFER_TYPE_STREAM         10  /* Complete wrap token */
 #define GSS_IOV_BUFFER_TYPE_SIGN_ONLY      11  /* Sign only packet data */
+#define GSS_IOV_BUFFER_TYPE_MIC_TOKEN      12  /* MIC token destination */
 
 #define GSS_IOV_BUFFER_FLAG_MASK           0xFFFF0000
 #define GSS_IOV_BUFFER_FLAG_ALLOCATE       0x00010000  /* indicates GSS should allocate */
@@ -325,6 +326,46 @@ OM_uint32 KRB5_CALLCONV gss_wrap_iov_length
     gss_iov_buffer_desc *, /* iov */
     int);              /* iov_count */
 
+/*
+ * Produce a GSSAPI MIC token for a sequence of buffers.  All SIGN_ONLY and
+ * DATA buffers will be signed, in the order they appear.  One MIC_TOKEN buffer
+ * must be included for the result.  Suitable space should be provided for the
+ * MIC_TOKEN buffer by calling gss_get_mic_iov_length, or the ALLOCATE flag
+ * should be set on that buffer.  If the ALLOCATE flag is used, use
+ * gss_release_iov_buffer to free the allocated buffer within the iov list when
+ * it is no longer needed.
+ */
+OM_uint32 KRB5_CALLCONV gss_get_mic_iov
+(
+    OM_uint32 *,       /* minor_status */
+    gss_ctx_id_t,      /* context_handle */
+    gss_qop_t,         /* qop_req */
+    gss_iov_buffer_desc *, /* iov */
+    int);              /* iov_count */
+
+/*
+ * Query the MIC_TOKEN buffer length within the iov list.
+ */
+OM_uint32 KRB5_CALLCONV gss_get_mic_iov_length(
+    OM_uint32 *,       /* minor_status */
+    gss_ctx_id_t,      /* context_handle */
+    gss_qop_t,         /* qop_req */
+    gss_iov_buffer_desc *, /* iov */
+    int);              /* iov_count */
+
+/*
+ * Verify the MIC_TOKEN buffer within the iov list against the SIGN_ONLY and
+ * DATA buffers in the order they appear.  Return values are the same as for
+ * gss_verify_mic.
+ */
+OM_uint32 KRB5_CALLCONV gss_verify_mic_iov
+(
+    OM_uint32 *,       /* minor_status */
+    gss_ctx_id_t,      /* context_handle */
+    gss_qop_t *,       /* qop_state */
+    gss_iov_buffer_desc *, /* iov */
+    int);              /* iov_count */
+
 /*
  * Release buffers that have the ALLOCATED flag set.
  */
index 310ff581959555f7576eab8793e7e9d82a9905ee..01678168f020203ccc98910c93a301b1404a3b0c 100644 (file)
@@ -403,6 +403,9 @@ gss_iov_buffer_t kg_locate_iov (gss_iov_buffer_desc *iov,
               int iov_count,
               OM_uint32 type);
 
+gss_iov_buffer_t kg_locate_header_iov(gss_iov_buffer_desc *iov, int iov_count,
+                                      int toktype);
+
 void kg_iov_msglen(gss_iov_buffer_desc *iov,
               int iov_count,
               size_t *data_length,
@@ -428,7 +431,8 @@ krb5_error_code kg_make_checksum_iov_v3(krb5_context context,
                 krb5_key key,
                 krb5_keyusage sign_usage,
                 gss_iov_buffer_desc *iov,
-                int iov_count);
+                int iov_count,
+                int toktype);
 
 krb5_error_code kg_verify_checksum_iov_v3(krb5_context context,
                 krb5_cksumtype type,
@@ -437,6 +441,7 @@ krb5_error_code kg_verify_checksum_iov_v3(krb5_context context,
                 krb5_keyusage sign_usage,
                 gss_iov_buffer_desc *iov,
                 int iov_count,
+                int toktype,
                 krb5_boolean *valid);
 
 OM_uint32 kg_seal_iov (OM_uint32 *minor_status,
@@ -462,7 +467,8 @@ OM_uint32 kg_seal_iov_length(OM_uint32 *minor_status,
            gss_qop_t qop_req,
            int *conf_state,
            gss_iov_buffer_desc *iov,
-           int iov_count);
+           int iov_count,
+           int toktype);
 
 krb5_cryptotype kg_translate_flag_iov(OM_uint32 type);
 
@@ -700,6 +706,22 @@ OM_uint32 KRB5_CALLCONV krb5_gss_get_mic
  gss_buffer_t                /* message_token */
 );
 
+OM_uint32 KRB5_CALLCONV krb5_gss_get_mic_iov
+(OM_uint32 *,                /* minor_status */
+ gss_ctx_id_t,               /* context_handle */
+ gss_qop_t,                  /* qop_req */
+ gss_iov_buffer_desc *,      /* iov */
+ int                         /* iov_count */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_get_mic_iov_length
+(OM_uint32 *,                /* minor_status */
+ gss_ctx_id_t,               /* context_handle */
+ gss_qop_t,                  /* qop_req */
+ gss_iov_buffer_desc *,      /* iov */
+ int                         /* iov_count */
+);
+
 OM_uint32 KRB5_CALLCONV krb5_gss_verify_mic
 (OM_uint32 *,           /* minor_status */
  gss_ctx_id_t,               /* context_handle */
@@ -708,6 +730,14 @@ OM_uint32 KRB5_CALLCONV krb5_gss_verify_mic
  gss_qop_t *                 /* qop_state */
 );
 
+OM_uint32 KRB5_CALLCONV krb5_gss_verify_mic_iov
+(OM_uint32 *,                /* minor_status */
+ gss_ctx_id_t,               /* context_handle */
+ gss_qop_t *,                /* qop_state */
+ gss_iov_buffer_desc *,      /* iov */
+ int                         /* iov_count */
+);
+
 OM_uint32 KRB5_CALLCONV krb5_gss_wrap
 (OM_uint32 *,           /* minor_status */
  gss_ctx_id_t,               /* context_handle */
index a1bb92dc05d5bb51eebf1523cbb5e999b13b020c..a408259cfbbe8f313335a78b8e0ac5cc76b4f2f1 100644 (file)
@@ -896,6 +896,12 @@ static struct gss_config krb5_mechanism = {
     krb5_gss_acquire_cred_with_password,
     krb5_gss_export_cred,
     krb5_gss_import_cred,
+    NULL,               /* import_sec_context_by_mech */
+    NULL,               /* import_name_by_mech */
+    NULL,               /* import_cred_by_mech */
+    krb5_gss_get_mic_iov,
+    krb5_gss_verify_mic_iov,
+    krb5_gss_get_mic_iov_length,
 };
 
 #ifdef _GSS_STATIC_LINK
index 3dafd1f5f9b98b828863c8f1097e3459c7fcfd6a..0b99a77e954fd0a0a592a5ced401afc0dae46ea0 100644 (file)
@@ -51,17 +51,16 @@ make_seal_token_v1_iov(krb5_context context,
     unsigned char *ptr;
     krb5_keyusage sign_usage = KG_USAGE_SIGN;
 
-    assert(toktype == KG_TOK_WRAP_MSG);
-
     md5cksum.length = cksum.length = 0;
     md5cksum.contents = cksum.contents = NULL;
 
-    header = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
+    header = kg_locate_header_iov(iov, iov_count, toktype);
     if (header == NULL)
         return EINVAL;
 
     padding = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
-    if (padding == NULL && (ctx->gss_flags & GSS_C_DCE_STYLE) == 0)
+    if (padding == NULL && toktype == KG_TOK_WRAP_MSG &&
+        (ctx->gss_flags & GSS_C_DCE_STYLE) == 0)
         return EINVAL;
 
     trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
@@ -171,7 +170,7 @@ make_seal_token_v1_iov(krb5_context context,
         goto cleanup;
     md5cksum.length = k5_trailerlen;
 
-    if (k5_headerlen != 0) {
+    if (k5_headerlen != 0 && toktype == KG_TOK_WRAP_MSG) {
         code = kg_make_confounder(context, ctx->enc->keyblock.enctype,
                                   ptr + 14 + ctx->cksum_size);
         if (code != 0)
@@ -332,7 +331,8 @@ kg_seal_iov_length(OM_uint32 *minor_status,
                    gss_qop_t qop_req,
                    int *conf_state,
                    gss_iov_buffer_desc *iov,
-                   int iov_count)
+                   int iov_count,
+                   int toktype)
 {
     krb5_gss_ctx_id_rec *ctx;
     gss_iov_buffer_t header, trailer, padding;
@@ -341,7 +341,7 @@ kg_seal_iov_length(OM_uint32 *minor_status,
     unsigned int k5_headerlen = 0, k5_trailerlen = 0, k5_padlen = 0;
     krb5_error_code code;
     krb5_context context;
-    int dce_style;
+    int dce_or_mic;
 
     if (qop_req != GSS_C_QOP_DEFAULT) {
         *minor_status = (OM_uint32)G_UNKNOWN_QOP;
@@ -354,7 +354,7 @@ kg_seal_iov_length(OM_uint32 *minor_status,
         return GSS_S_NO_CONTEXT;
     }
 
-    header = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
+    header = kg_locate_header_iov(iov, iov_count, toktype);
     if (header == NULL) {
         *minor_status = EINVAL;
         return GSS_S_FAILURE;
@@ -366,12 +366,15 @@ kg_seal_iov_length(OM_uint32 *minor_status,
         INIT_IOV_DATA(trailer);
     }
 
-    dce_style = ((ctx->gss_flags & GSS_C_DCE_STYLE) != 0);
+    /* MIC tokens and DCE-style wrap tokens have similar length considerations:
+     * no padding, and the framing surrounds the header only, not the data. */
+    dce_or_mic = ((ctx->gss_flags & GSS_C_DCE_STYLE) != 0 ||
+                  toktype == KG_TOK_MIC_MSG);
 
     /* For CFX, EC is used instead of padding, and is placed in header or trailer */
     padding = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
     if (padding == NULL) {
-        if (conf_req_flag && ctx->proto == 0 && !dce_style) {
+        if (conf_req_flag && ctx->proto == 0 && !dce_or_mic) {
             *minor_status = EINVAL;
             return GSS_S_FAILURE;
         }
@@ -425,7 +428,7 @@ kg_seal_iov_length(OM_uint32 *minor_status,
                 return GSS_S_FAILURE;
             }
 
-            if (k5_padlen == 0 && dce_style) {
+            if (k5_padlen == 0 && dce_or_mic) {
                 /* Windows rejects AEAD tokens with non-zero EC */
                 code = krb5_c_block_size(context, enctype, &ec);
                 if (code != 0) {
@@ -439,7 +442,7 @@ kg_seal_iov_length(OM_uint32 *minor_status,
         } else {
             gss_trailerlen = k5_trailerlen; /* Kerb-Checksum */
         }
-    } else if (!dce_style) {
+    } else if (!dce_or_mic) {
         k5_padlen = (ctx->sealalg == SEAL_ALG_MICROSOFT_RC4) ? 1 : 8;
 
         if (k5_padlen == 1)
@@ -458,14 +461,14 @@ kg_seal_iov_length(OM_uint32 *minor_status,
 
         data_size = 14 /* Header */ + ctx->cksum_size + k5_headerlen;
 
-        if (!dce_style)
+        if (!dce_or_mic)
             data_size += data_length;
 
         gss_headerlen = g_token_size(ctx->mech_used, data_size);
 
         /* g_token_size() will include data_size as well as the overhead, so
          * subtract data_length just to get the overhead (ie. token size) */
-        if (!dce_style)
+        if (!dce_or_mic)
             gss_headerlen -= data_length;
     }
 
@@ -519,13 +522,13 @@ krb5_gss_wrap_iov_length(OM_uint32 *minor_status,
 {
     OM_uint32 major_status;
 
-    major_status = kg_seal_iov_length(minor_status, context_handle, conf_req_flag,
-                                      qop_req, conf_state, iov, iov_count);
+    major_status = kg_seal_iov_length(minor_status, context_handle,
+                                      conf_req_flag, qop_req, conf_state, iov,
+                                      iov_count, KG_TOK_WRAP_MSG);
     return major_status;
 }
 
-#if 0
-OM_uint32
+OM_uint32 KRB5_CALLCONV
 krb5_gss_get_mic_iov(OM_uint32 *minor_status,
                      gss_ctx_id_t context_handle,
                      gss_qop_t qop_req,
@@ -541,19 +544,17 @@ krb5_gss_get_mic_iov(OM_uint32 *minor_status,
     return major_status;
 }
 
-OM_uint32
+OM_uint32 KRB5_CALLCONV
 krb5_gss_get_mic_iov_length(OM_uint32 *minor_status,
                             gss_ctx_id_t context_handle,
-                            int conf_req_flag,
                             gss_qop_t qop_req,
-                            int *conf_state,
                             gss_iov_buffer_desc *iov,
                             int iov_count)
 {
     OM_uint32 major_status;
 
-    major_status = kg_seal_iov_length(minor_status, context_handle, conf_req_flag,
-                                      qop_req, conf_state, iov, iov_count);
+    major_status = kg_seal_iov_length(minor_status, context_handle, FALSE,
+                                      qop_req, NULL, iov, iov_count,
+                                      KG_TOK_MIC_MSG);
     return major_status;
 }
-#endif
index d7c92875ee9532cf814340106119b254e6b1e454..8f6c4d441333a4805ea821e2d137bb6852764cc4 100644 (file)
@@ -76,7 +76,7 @@ gss_krb5int_make_seal_token_v3_iov(krb5_context context,
 
     kg_iov_msglen(iov, iov_count, &data_length, &assoc_data_length);
 
-    header = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
+    header = kg_locate_header_iov(iov, iov_count, toktype);
     if (header == NULL)
         return EINVAL;
 
@@ -240,7 +240,7 @@ gss_krb5int_make_seal_token_v3_iov(krb5_context context,
 
         code = kg_make_checksum_iov_v3(context, cksumtype,
                                        rrc, key, key_usage,
-                                       iov, iov_count);
+                                       iov, iov_count, toktype);
         if (code != 0)
             goto cleanup;
 
@@ -302,7 +302,7 @@ gss_krb5int_unseal_v3_iov(krb5_context context,
     if (qop_state != NULL)
         *qop_state = GSS_C_QOP_DEFAULT;
 
-    header = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
+    header = kg_locate_header_iov(iov, iov_count, toktype);
     assert(header != NULL);
 
     padding = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
@@ -421,7 +421,7 @@ gss_krb5int_unseal_v3_iov(krb5_context context,
 
             code = kg_verify_checksum_iov_v3(context, cksumtype, rrc,
                                              key, key_usage,
-                                             iov, iov_count, &valid);
+                                             iov, iov_count, toktype, &valid);
             if (code != 0 || valid == FALSE) {
                 *minor_status = code;
                 return GSS_S_BAD_SIG;
@@ -438,9 +438,12 @@ gss_krb5int_unseal_v3_iov(krb5_context context,
             goto defective;
         seqnum = load_64_be(ptr + 8);
 
-        code = kg_verify_checksum_iov_v3(context, cksumtype, 0,
+        /* For MIC tokens, the GSS header and checksum are in the same buffer.
+         * Fake up an RRC so that the checksum is expected in the header. */
+        rrc = (trailer != NULL) ? 0 : header->buffer.length - 16;
+        code = kg_verify_checksum_iov_v3(context, cksumtype, rrc,
                                          key, key_usage,
-                                         iov, iov_count, &valid);
+                                         iov, iov_count, toktype, &valid);
         if (code != 0 || valid == FALSE) {
             *minor_status = code;
             return GSS_S_BAD_SIG;
index f80f4d05d60d591c1e0d709e8c32fcffff0af912..24853abeca0ab872cd57fa3192940eb428724851 100644 (file)
@@ -57,12 +57,10 @@ kg_unseal_v1_iov(krb5_context context,
     size_t sumlen;
     krb5_keyusage sign_usage = KG_USAGE_SIGN;
 
-    assert(toktype == KG_TOK_WRAP_MSG);
-
     md5cksum.length = cksum.length = 0;
     md5cksum.contents = cksum.contents = NULL;
 
-    header = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
+    header = kg_locate_header_iov(iov, iov_count, toktype);
     assert(header != NULL);
 
     trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
@@ -316,7 +314,7 @@ kg_unseal_iov_token(OM_uint32 *minor_status,
     unsigned int bodysize;
     int toktype2;
 
-    header = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
+    header = kg_locate_header_iov(iov, iov_count, toktype);
     if (header == NULL) {
         *minor_status = EINVAL;
         return GSS_S_FAILURE;
@@ -328,7 +326,8 @@ kg_unseal_iov_token(OM_uint32 *minor_status,
     ptr = (unsigned char *)header->buffer.value;
     input_length = header->buffer.length;
 
-    if ((ctx->gss_flags & GSS_C_DCE_STYLE) == 0) {
+    if ((ctx->gss_flags & GSS_C_DCE_STYLE) == 0 &&
+        toktype == KG_TOK_WRAP_MSG) {
         size_t data_length, assoc_data_length;
 
         kg_iov_msglen(iov, iov_count, &data_length, &assoc_data_length);
@@ -655,8 +654,7 @@ krb5_gss_unwrap_iov(OM_uint32 *minor_status,
     return major_status;
 }
 
-#if 0
-OM_uint32
+OM_uint32 KRB5_CALLCONV
 krb5_gss_verify_mic_iov(OM_uint32 *minor_status,
                         gss_ctx_id_t context_handle,
                         gss_qop_t *qop_state,
@@ -667,8 +665,7 @@ krb5_gss_verify_mic_iov(OM_uint32 *minor_status,
 
     major_status = kg_unseal_iov(minor_status, context_handle,
                                  NULL, qop_state,
-                                 iov, iov_count, KG_TOK_WRAP_MSG);
+                                 iov, iov_count, KG_TOK_MIC_MSG);
 
     return major_status;
 }
-#endif
index 4877c71ebbcd478359669244bdbb7be83da187cf..cfd585ec721935c814d209d865d4d8ea1da29fa5 100644 (file)
@@ -122,15 +122,13 @@ kg_make_checksum_iov_v1(krb5_context context,
     krb5_error_code code;
     gss_iov_buffer_desc *header;
     krb5_crypto_iov *kiov;
-    size_t kiov_count;
     int i = 0, j;
     size_t conf_len = 0, token_header_len;
 
-    header = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
+    header = kg_locate_header_iov(iov, iov_count, toktype);
     assert(header != NULL);
 
-    kiov_count = 3 + iov_count;
-    kiov = (krb5_crypto_iov *)xmalloc(kiov_count * sizeof(krb5_crypto_iov));
+    kiov = calloc(iov_count + 3, sizeof(krb5_crypto_iov));
     if (kiov == NULL)
         return ENOMEM;
 
@@ -172,7 +170,7 @@ kg_make_checksum_iov_v1(krb5_context context,
         i++;
     }
 
-    code = krb5_k_make_checksum_iov(context, type, seq, sign_usage, kiov, kiov_count);
+    code = krb5_k_make_checksum_iov(context, type, seq, sign_usage, kiov, i);
     if (code == 0) {
         checksum->length = kiov[0].data.length;
         checksum->contents = (unsigned char *)kiov[0].data.data;
@@ -192,6 +190,7 @@ checksum_iov_v3(krb5_context context,
                 krb5_keyusage sign_usage,
                 gss_iov_buffer_desc *iov,
                 int iov_count,
+                int toktype,
                 krb5_boolean verify,
                 krb5_boolean *valid)
 {
@@ -210,7 +209,7 @@ checksum_iov_v3(krb5_context context,
     if (code != 0)
         return code;
 
-    header = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
+    header = kg_locate_header_iov(iov, iov_count, toktype);
     assert(header != NULL);
 
     trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
@@ -273,10 +272,11 @@ kg_make_checksum_iov_v3(krb5_context context,
                         krb5_key key,
                         krb5_keyusage sign_usage,
                         gss_iov_buffer_desc *iov,
-                        int iov_count)
+                        int iov_count,
+                        int toktype)
 {
     return checksum_iov_v3(context, type, rrc, key,
-                           sign_usage, iov, iov_count, 0, NULL);
+                           sign_usage, iov, iov_count, toktype, 0, NULL);
 }
 
 krb5_error_code
@@ -287,8 +287,9 @@ kg_verify_checksum_iov_v3(krb5_context context,
                           krb5_keyusage sign_usage,
                           gss_iov_buffer_desc *iov,
                           int iov_count,
+                          int toktype,
                           krb5_boolean *valid)
 {
     return checksum_iov_v3(context, type, rrc, key,
-                           sign_usage, iov, iov_count, 1, valid);
+                           sign_usage, iov, iov_count, toktype, 1, valid);
 }
index b7b4a0a605ec44a439b6b9cc5dd1b29eb80bfc4b..055093cd72e8e18adf89c52e360d2048c95dc91b 100644 (file)
@@ -626,6 +626,17 @@ kg_locate_iov(gss_iov_buffer_desc *iov, int iov_count, OM_uint32 type)
     return p;
 }
 
+/* Return the IOV where the GSSAPI token header should be placed (and possibly
+ * the checksum as well, depending on the token type). */
+gss_iov_buffer_t
+kg_locate_header_iov(gss_iov_buffer_desc *iov, int iov_count, int toktype)
+{
+    if (toktype == KG_TOK_MIC_MSG)
+        return kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_MIC_TOKEN);
+    else
+        return kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
+}
+
 void
 kg_iov_msglen(gss_iov_buffer_desc *iov, int iov_count, size_t *data_length_p,
               size_t *assoc_data_length_p)
index 242a3c0dc8be5355071bb9c0ccb8780aee8157fc..4929c71014a18f25763e477bb62a585b9f0d7612 100644 (file)
@@ -65,6 +65,8 @@ gss_export_name
 gss_export_name_composite
 gss_export_sec_context
 gss_get_mic
+gss_get_mic_iov
+gss_get_mic_iov_length
 gss_get_name_attribute
 gss_import_cred
 gss_import_name
@@ -139,6 +141,7 @@ gss_unwrap_iov
 gss_userok
 gss_verify
 gss_verify_mic
+gss_verify_mic_iov
 gss_wrap
 gss_wrap_aead
 gss_wrap_iov
index aad9c76958e94d0509594c5668a2d984f444e200..9b95c0162cc2d57359bb34293279f8569db3ba73 100644 (file)
@@ -111,3 +111,28 @@ int                        iov_count;
 
     return (GSS_S_BAD_MECH);
 }
+
+OM_uint32 KRB5_CALLCONV
+gss_verify_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+                  gss_qop_t *qop_state, gss_iov_buffer_desc *iov,
+                  int iov_count)
+{
+    OM_uint32 status;
+    gss_union_ctx_id_t ctx;
+    gss_mechanism mech;
+
+    status = val_unwrap_iov_args(minor_status, context_handle, NULL,
+                                qop_state, iov, iov_count);
+    if (status != GSS_S_COMPLETE)
+       return status;
+
+    /* Select the approprate underlying mechanism routine and call it. */
+    ctx = (gss_union_ctx_id_t)context_handle;
+    mech = gssint_get_mechanism(ctx->mech_type);
+    if (mech == NULL)
+       return GSS_S_BAD_MECH;
+    if (mech->gss_verify_mic_iov == NULL)
+       return GSS_S_UNAVAILABLE;
+    return mech->gss_verify_mic_iov(minor_status, ctx->internal_ctx_id,
+                                   qop_state, iov, iov_count);
+}
index 9586c587e7e493c85c30f2d975041f11b782318e..17a2537e0e5c97da8a2e33c974508b47026aa637 100644 (file)
@@ -175,6 +175,55 @@ int                        iov_count;
     return (GSS_S_BAD_MECH);
 }
 
+OM_uint32 KRB5_CALLCONV
+gss_get_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+               gss_qop_t qop_req, gss_iov_buffer_desc *iov, int iov_count)
+{
+    OM_uint32 status;
+    gss_union_ctx_id_t ctx;
+    gss_mechanism mech;
+
+    status = val_wrap_iov_args(minor_status, context_handle, 0, qop_req, NULL,
+                              iov, iov_count);
+    if (status != GSS_S_COMPLETE)
+       return status;
+
+    /* Select the approprate underlying mechanism routine and call it. */
+    ctx = (gss_union_ctx_id_t)context_handle;
+    mech = gssint_get_mechanism(ctx->mech_type);
+    if (mech == NULL)
+       return GSS_S_BAD_MECH;
+    if (mech->gss_get_mic_iov == NULL)
+       return GSS_S_UNAVAILABLE;
+    return mech->gss_get_mic_iov(minor_status, ctx->internal_ctx_id, qop_req,
+                                iov, iov_count);
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_get_mic_iov_length(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+                      gss_qop_t qop_req, gss_iov_buffer_desc *iov,
+                      int iov_count)
+{
+    OM_uint32 status;
+    gss_union_ctx_id_t ctx;
+    gss_mechanism mech;
+
+    status = val_wrap_iov_args(minor_status, context_handle, 0, qop_req, NULL,
+                              iov, iov_count);
+    if (status != GSS_S_COMPLETE)
+       return status;
+
+    /* Select the approprate underlying mechanism routine and call it. */
+    ctx = (gss_union_ctx_id_t)context_handle;
+    mech = gssint_get_mechanism(ctx->mech_type);
+    if (mech == NULL)
+       return GSS_S_BAD_MECH;
+    if (mech->gss_get_mic_iov_length == NULL)
+       return GSS_S_UNAVAILABLE;
+    return mech->gss_get_mic_iov_length(minor_status, ctx->internal_ctx_id,
+                                       qop_req, iov, iov_count);
+}
+
 OM_uint32 KRB5_CALLCONV
 gss_release_iov_buffer (minor_status,
                        iov,
index 9e02474a82d8f1dcd0304c54d333c9ca19bd61fb..e56b9c1a58f1b04542dfd433630db46c2a2e65a9 100644 (file)
@@ -674,6 +674,35 @@ typedef struct gss_config {
            gss_cred_id_t *             /* cred_handle */
        /* */);
 
+       /* get_mic_iov extensions, added in 1.12 */
+
+       OM_uint32       (KRB5_CALLCONV *gss_get_mic_iov)
+       (
+           OM_uint32 *,                /* minor_status */
+           gss_ctx_id_t,               /* context_handle */
+           gss_qop_t,                  /* qop_req */
+           gss_iov_buffer_desc *,      /* iov */
+           int                         /* iov_count */
+       );
+
+       OM_uint32       (KRB5_CALLCONV *gss_verify_mic_iov)
+       (
+           OM_uint32 *,                /* minor_status */
+           gss_ctx_id_t,               /* context_handle */
+           gss_qop_t *,                /* qop_state */
+           gss_iov_buffer_desc *,      /* iov */
+           int                         /* iov_count */
+       );
+
+       OM_uint32       (KRB5_CALLCONV *gss_get_mic_iov_length)
+       (
+           OM_uint32 *,                /* minor_status */
+           gss_ctx_id_t,               /* context_handle */
+           gss_qop_t,                  /* qop_req */
+           gss_iov_buffer_desc *,      /* iov */
+           int                         /* iov_count */
+       );
+
 } *gss_mechanism;
 
 /*
index 9d8fe52c92d14db17fe4241a57255b71168ad3c2..bc23f567172e990333dd90e59d629347e10c2cd5 100644 (file)
@@ -629,6 +629,33 @@ spnego_gss_import_cred(
        gss_cred_id_t *cred_handle
 );
 
+OM_uint32 KRB5_CALLCONV
+spnego_gss_get_mic_iov(
+       OM_uint32 *minor_status,
+       gss_ctx_id_t context_handle,
+       gss_qop_t qop_req,
+       gss_iov_buffer_desc *iov,
+       int iov_count
+);
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_verify_mic_iov(
+       OM_uint32 *minor_status,
+       gss_ctx_id_t context_handle,
+       gss_qop_t *qop_state,
+       gss_iov_buffer_desc *iov,
+       int iov_count
+);
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_get_mic_iov_length(
+       OM_uint32 *minor_status,
+       gss_ctx_id_t context_handle,
+       gss_qop_t qop_req,
+       gss_iov_buffer_desc *iov,
+       int iov_count
+);
+
 #ifdef __cplusplus
 }
 #endif
index 33c8c88080eb4cda0e59571fc741f52bb641fdca..24c344066d245bdc08e288adad122daa150f4a4d 100644 (file)
@@ -280,6 +280,12 @@ static struct gss_config spnego_mechanism =
        spnego_gss_acquire_cred_with_password,
        spnego_gss_export_cred,
        spnego_gss_import_cred,
+       NULL,                           /* gssspi_import_sec_context_by_mech */
+       NULL,                           /* gssspi_import_name_by_mech */
+       NULL,                           /* gssspi_import_cred_by_mech */
+       spnego_gss_get_mic_iov,
+       spnego_gss_verify_mic_iov,
+       spnego_gss_get_mic_iov_length
 };
 
 #ifdef _GSS_STATIC_LINK
@@ -2837,6 +2843,33 @@ spnego_gss_import_cred(OM_uint32 *minor_status,
        return (ret);
 }
 
+OM_uint32 KRB5_CALLCONV
+spnego_gss_get_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+                      gss_qop_t qop_req, gss_iov_buffer_desc *iov,
+                      int iov_count)
+{
+    return gss_get_mic_iov(minor_status, context_handle, qop_req, iov,
+                          iov_count);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_verify_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+                         gss_qop_t *qop_state, gss_iov_buffer_desc *iov,
+                         int iov_count)
+{
+    return gss_verify_mic_iov(minor_status, context_handle, qop_state, iov,
+                             iov_count);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_get_mic_iov_length(OM_uint32 *minor_status,
+                             gss_ctx_id_t context_handle, gss_qop_t qop_req,
+                             gss_iov_buffer_desc *iov, int iov_count)
+{
+    return gss_get_mic_iov_length(minor_status, context_handle, qop_req, iov,
+                                 iov_count);
+}
+
 /*
  * We will release everything but the ctx_handle so that it
  * can be passed back to init/accept context. This routine should
index 00c707474b76c1b5a80ec05950039c0fff09d78b..9e18a6692050bed4ee00e07e22e542b173482b8f 100644 (file)
@@ -176,3 +176,7 @@ EXPORTS
        gss_store_cred_into                             @141
        gss_export_cred                                 @142
        gss_import_cred                                 @143
+; Added in 1.12
+       gss_get_mic_iov                                 @144
+       gss_get_mic_iov_length                          @145
+       gss_verify_mic_iov                              @146
index 9c6d5703e6a2f76080a7fef8ff70cc239fedb6ef..f900b8835f79c3b4057c4b0fc6b70834be36817f 100644 (file)
@@ -351,6 +351,91 @@ test_aead(gss_ctx_id_t ctx1, gss_ctx_id_t ctx2, int conf)
     (void)gss_release_iov_buffer(&minor, stiov, 3);
 }
 
+/*
+ * Get a MIC for sign1, sign2, and sign3 using the caller-provided array iov,
+ * which must have space for four elements, and the caller-provided buffer
+ * data, which must be big enough for the MIC.  If data is NULL, the library
+ * will be asked to allocate the MIC buffer.  The MIC will be located in
+ * iov[3].buffer.
+ */
+static void
+mic(gss_ctx_id_t ctx, const char *sign1, const char *sign2, const char *sign3,
+    gss_iov_buffer_desc *iov, char *data)
+{
+    OM_uint32 minor, major;
+    krb5_boolean allocated;
+
+    /* Lay out iov array. */
+    iov[0].type = GSS_IOV_BUFFER_TYPE_DATA;
+    iov[0].buffer.value = (char *)sign1;
+    iov[0].buffer.length = strlen(sign1);
+    iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
+    iov[1].buffer.value = (char *)sign2;
+    iov[1].buffer.length = strlen(sign2);
+    iov[2].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
+    iov[2].buffer.value = (char *)sign3;
+    iov[2].buffer.length = strlen(sign3);
+    iov[3].type = GSS_IOV_BUFFER_TYPE_MIC_TOKEN;
+    if (data == NULL) {
+        /* Ask the library to allocate the MIC buffer. */
+        iov[3].type |= GSS_IOV_BUFFER_FLAG_ALLOCATE;
+    } else {
+        /* Get the MIC length and use the caller-provided buffer. */
+        major = gss_get_mic_iov_length(&minor, ctx, GSS_C_QOP_DEFAULT, iov, 4);
+        check_gsserr("gss_get_mic_iov_length", major, minor);
+        iov[3].buffer.value = data;
+    }
+    major = gss_get_mic_iov(&minor, ctx, GSS_C_QOP_DEFAULT, iov, 4);
+    check_gsserr("gss_get_mic_iov", major, minor);
+    allocated = (GSS_IOV_BUFFER_FLAGS(iov[3].type) &
+                 GSS_IOV_BUFFER_FLAG_ALLOCATED) != 0;
+    if (allocated != (data == NULL))
+        errout("gss_get_mic_iov allocated");
+}
+
+static void
+test_mic(gss_ctx_id_t ctx1, gss_ctx_id_t ctx2)
+{
+    OM_uint32 major, minor;
+    gss_iov_buffer_desc iov[4];
+    gss_qop_t qop;
+    gss_buffer_desc concatbuf, micbuf;
+    const char *sign1 = "Data and sign-only ";
+    const char *sign2 = "buffers are treated ";
+    const char *sign3 = "equally by gss_get_mic_iov";
+    char concat[1024], data[1024];
+
+    (void)snprintf(concat, sizeof(concat), "%s%s%s", sign1, sign2, sign3);
+    concatbuf.value = concat;
+    concatbuf.length = strlen(concat);
+
+    /* MIC with a caller-provided buffer and verify with the IOV array. */
+    mic(ctx1, sign1, sign2, sign3, iov, data);
+    major = gss_verify_mic_iov(&minor, ctx2, &qop, iov, 4);
+    check_gsserr("gss_verify_mic_iov(mic1)", major, minor);
+    if (qop != GSS_C_QOP_DEFAULT)
+        errout("gss_verify_mic_iov(mic1) qop");
+
+    /* MIC with an allocated buffer and verify with gss_verify_mic. */
+    mic(ctx1, sign1, sign2, sign3, iov, NULL);
+    major = gss_verify_mic(&minor, ctx2, &concatbuf, &iov[3].buffer, &qop);
+    check_gsserr("gss_verify_mic(mic2)", major, minor);
+    if (qop != GSS_C_QOP_DEFAULT)
+        errout("gss_verify_mic(mic2) qop");
+    (void)gss_release_iov_buffer(&minor, iov, 4);
+
+    /* MIC with gss_c_get_mic and verify using the IOV array (which is still
+     * mostly set up from the last call to mic(). */
+    major = gss_get_mic(&minor, ctx1, GSS_C_QOP_DEFAULT, &concatbuf, &micbuf);
+    check_gsserr("gss_get_mic(mic3)", major, minor);
+    iov[3].buffer = micbuf;
+    major = gss_verify_mic_iov(&minor, ctx2, &qop, iov, 4);
+    check_gsserr("gss_verify_mic_iov(mic3)", major, minor);
+    if (qop != GSS_C_QOP_DEFAULT)
+        errout("gss_verify_mic_iov(mic3) qop");
+    (void)gss_release_buffer(&minor, &micbuf);
+}
+
 /* Create a DCE-style token and make sure we can unwrap it. */
 static void
 test_dce(gss_ctx_id_t ctx1, gss_ctx_id_t ctx2, int conf)
@@ -440,6 +525,10 @@ main(int argc, char *argv[])
     test_aead(actx, ictx, 0);
     test_aead(actx, ictx, 1);
 
+    /* Test MIC tokens. */
+    test_mic(ictx, actx);
+    test_mic(actx, ictx);
+
     /* Test DCE wrapping with DCE-style contexts. */
     (void)gss_delete_sec_context(&minor, &ictx, NULL);
     (void)gss_delete_sec_context(&minor, &actx, NULL);