Patch from Luke Howard to:
authorSam Hartman <hartmans@mit.edu>
Tue, 13 Jan 2009 22:57:42 +0000 (22:57 +0000)
committerSam Hartman <hartmans@mit.edu>
Tue, 13 Jan 2009 22:57:42 +0000 (22:57 +0000)
* Accept both CFX and non-CFX tokens all the time on acceptor
* Only produce an acceptor subkey if you are using cfx or dce or negotiating up to cfx

Additional changes from Sam Hartman:
* do not assume that the ticket  key type (server key) is a valid target for negotiation: the client may not support it.

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@21742 dc483132-0cff-0310-8789-dd5450dbe970

src/include/k5-int.h
src/lib/gssapi/krb5/accept_sec_context.c
src/lib/gssapi/krb5/k5sealv3.c
src/lib/gssapi/krb5/k5sealv3iov.c
src/lib/gssapi/krb5/k5unseal.c
src/lib/gssapi/krb5/k5unsealiov.c
src/lib/gssapi/krb5/util_crypt.c
src/lib/krb5/krb/auth_con.c
src/lib/krb5/krb/rd_req_dec.c
src/lib/krb5/os/accessor.c

index 9ad55694e3ea089188322093a3e5efad9d0504f6..072a4d397aff27fbdc4330121ce1e3700a85884a 100644 (file)
@@ -1959,7 +1959,7 @@ void krb5int_free_srv_dns_data(struct srv_dns_entry *);
 /* To keep happy libraries which are (for now) accessing internal stuff */
 
 /* Make sure to increment by one when changing the struct */
-#define KRB5INT_ACCESS_STRUCT_VERSION 12
+#define KRB5INT_ACCESS_STRUCT_VERSION 13
 
 #ifndef ANAME_SZ
 struct ktext;                  /* from krb.h, for krb524 support */
@@ -1972,6 +1972,7 @@ typedef struct _krb5int_access {
                                   const krb5_keyblock *key,
                                   unsigned int icount, const krb5_data *input,
                                   krb5_data *output);
+    krb5_error_code (* krb5_auth_con_get_subkey_enctype)(krb5_context, krb5_auth_context, krb5_enctype *);
     /* service location and communication */
     krb5_error_code (*sendto_udp) (krb5_context, const krb5_data *msg,
                                   const struct addrlist *, struct sendto_callback_info*, krb5_data *reply,
@@ -2580,6 +2581,11 @@ krb5_error_code krb5_auth_con_getpermetypes
            krb5_auth_context,
            krb5_enctype **);
 
+krb5_error_code krb5_auth_con_get_subkey_enctype
+       (krb5_context context,
+           krb5_auth_context,
+           krb5_enctype *);
+
 krb5_error_code KRB5_CALLCONV
 krb5int_server_decrypt_ticket_keyblock
        (krb5_context context,
index 2e2433a2a000d6203236f8d908d40d3042b1be55..63ce92c1bbc6712179c7a97955d96bc22e44863c 100644 (file)
@@ -395,6 +395,7 @@ kg_accept_krb5(minor_status, context_handle,
     int cred_rcache = 0;
     int no_encap = 0;
     krb5_flags ap_req_options = 0;
+    krb5_enctype negotiated_etype;
 
     code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
     if (code) {
@@ -903,6 +904,34 @@ kg_accept_krb5(minor_status, context_handle,
         krb5_int32 seq_temp;
         int cfx_generate_subkey;
 
+       /*
+        * Do not generate a subkey per RFC 4537 unless we are upgrading to CFX,
+        * because pre-CFX tokens do not indicate which key to use. (Note that
+        * DCE_STYLE implies that we will use a subkey.)
+        */
+       if (ctx->proto == 0 &&
+           (ctx->gss_flags & GSS_C_DCE_STYLE) == 0 && 
+           (ap_req_options & AP_OPTS_USE_SUBKEY)) {
+           code = (*kaccess.krb5_auth_con_get_subkey_enctype) (context,
+                                                               auth_context,
+                                                               &negotiated_etype);
+           if (code != 0) {
+               major_status = GSS_S_FAILURE;
+               goto fail;
+           }
+
+           switch (negotiated_etype) {
+           case ENCTYPE_DES_CBC_MD5:
+           case ENCTYPE_DES_CBC_MD4:
+           case ENCTYPE_DES_CBC_CRC:
+           case ENCTYPE_DES3_CBC_SHA1:
+           case ENCTYPE_ARCFOUR_HMAC:
+           case ENCTYPE_ARCFOUR_HMAC_EXP:
+               ap_req_options &= ~(AP_OPTS_USE_SUBKEY);
+               break;
+           }
+       }
+
         if (ctx->proto == 1 || (ctx->gss_flags & GSS_C_DCE_STYLE) ||
            (ap_req_options & AP_OPTS_USE_SUBKEY))
             cfx_generate_subkey = CFX_ACCEPTOR_SUBKEY;
index 71e832e15bd5e1b6568a8c474f8df24962a56e3a..56a4a4462db841ccb153ef738213780924c7e180 100644 (file)
@@ -320,8 +320,9 @@ gss_krb5int_unseal_token_v3(krb5_context *contextptr,
     krb5_keyblock *key;
     krb5_cksumtype cksumtype;
 
-    assert(ctx->big_endian == 0);
-    assert(ctx->proto == 1);
+    if(ctx->big_endian != 0)
+      goto defective;
+
 
     if (qop_state)
         *qop_state = GSS_C_QOP_DEFAULT;
index 41e6132cd915643e57a233836ba80ec80f3d222d..879d99748d15047574fbd9529765b1a7c96b0f6f 100644 (file)
@@ -297,8 +297,9 @@ gss_krb5int_unseal_v3_iov(krb5_context context,
     krb5_cksumtype cksumtype;
     int conf_flag = 0;
 
-    assert(ctx->big_endian == 0);
-    assert(ctx->proto == 1);
+    if (ctx->big_endian != 0)
+        return GSS_S_DEFECTIVE_TOKEN;
+
 
     if (qop_state != NULL)
        *qop_state = GSS_C_QOP_DEFAULT;
index 4b70fd02ad6bbe95fdd7c4275503c6c3a33e5570..a94ac9ef053782cc45aeaba7388feb4b27c46943 100644 (file)
@@ -494,6 +494,7 @@ kg_unseal(minor_status, context_handle, input_token_buffer,
     unsigned int bodysize;
     int err;
     int toktype2;
+    int vfyflags = 0;
     OM_uint32 ret;
 
     /* validate the context handle */
@@ -515,26 +516,49 @@ kg_unseal(minor_status, context_handle, input_token_buffer,
 
     ptr = (unsigned char *) input_token_buffer->value;
 
-    toktype2 = kg_map_toktype(ctx->proto, toktype);
 
     err = g_verify_token_header(ctx->mech_used,
-                                &bodysize, &ptr, toktype2,
+                                &bodysize, &ptr, -1,
                                 input_token_buffer->length,
-                                !ctx->proto);
+                                vfyflags);
     if (err) {
         *minor_status = err;
         return GSS_S_DEFECTIVE_TOKEN;
     }
 
-    if (ctx->proto == 0)
-        ret = kg_unseal_v1(ctx->k5_context, minor_status, ctx, ptr, bodysize,
-                           message_buffer, conf_state, qop_state,
-                           toktype);
-    else
+    if (bodysize < 2) {
+       *minor_status = (OM_uint32)G_BAD_TOK_HEADER;
+       return GSS_S_DEFECTIVE_TOKEN;
+    }
+
+    toktype2 = load_16_be(ptr);
+
+    ptr += 2;
+    bodysize -= 2;
+
+    switch (toktype2) {
+    case KG2_TOK_MIC_MSG:
+    case KG2_TOK_WRAP_MSG:
+    case KG2_TOK_DEL_CTX:
         ret = gss_krb5int_unseal_token_v3(&ctx->k5_context, minor_status, ctx,
                                           ptr, bodysize, message_buffer,
                                           conf_state, qop_state, toktype);
+       break;
+    case KG_TOK_MIC_MSG:
+    case KG_TOK_WRAP_MSG:
+    case KG_TOK_DEL_CTX:
+        ret = kg_unseal_v1(ctx->k5_context, minor_status, ctx, ptr, bodysize,
+                           message_buffer, conf_state, qop_state,
+                           toktype);
+       break;
+    default:
+       *minor_status = (OM_uint32)G_BAD_TOK_HEADER;
+       ret = GSS_S_DEFECTIVE_TOKEN;
+       break;
+    }
+
     if (ret != 0)
         save_error_info (*minor_status, ctx->k5_context);
+
     return ret;
 }
index c72e2db39c38eee66d1b38682bf5c46f8b1becab..a9d4c9effb68d4ec58a4c68e872e45c7d3aa032b 100644 (file)
@@ -172,7 +172,7 @@ kg_unseal_v1_iov(krb5_context context,
                                              iov, iov_count);
                krb5_free_keyblock(context, enc_key);
            } else {
-               code = kg_decrypt_iov(context, ctx->proto,
+               code = kg_decrypt_iov(context, 0,
                                      ((ctx->gss_flags & GSS_C_DCE_STYLE) != 0),
                                      0 /*EC*/, 0 /*RRC*/,
                                      ctx->enc, KG_USAGE_SEAL, NULL,
@@ -325,8 +325,7 @@ kg_unseal_iov_token(OM_uint32 *minor_status,
                    gss_qop_t *qop_state,
                    gss_iov_buffer_desc *iov,
                    int iov_count,
-                   int toktype,
-                   int toktype2)
+                   int toktype)
 {
     krb5_error_code code;
     krb5_context context = ctx->k5_context;
@@ -336,6 +335,7 @@ kg_unseal_iov_token(OM_uint32 *minor_status,
     gss_iov_buffer_t trailer;
     size_t input_length;
     unsigned int bodysize;
+    int toktype2;
     int vfyflags = 0;
 
     header = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
@@ -364,26 +364,46 @@ kg_unseal_iov_token(OM_uint32 *minor_status,
            input_length += trailer->buffer.length;
     }
 
-    if (ctx->proto == 0)
-       vfyflags |= G_VFY_TOKEN_HDR_WRAPPER_REQUIRED;
     if (ctx->gss_flags & GSS_C_DCE_STYLE)
        vfyflags |= G_VFY_TOKEN_HDR_IGNORE_SEQ_SIZE;
 
     code = g_verify_token_header(ctx->mech_used,
-                                &bodysize, &ptr, toktype2,
-                                input_length, vfyflags);
+                                &bodysize, &ptr, -1,
+                                input_length, 0);
     if (code != 0) {
-       *minor_status = code;
+        *minor_status = code;
+        return GSS_S_DEFECTIVE_TOKEN;
+    }
+
+    if (bodysize < 2) {
+       *minor_status = (OM_uint32)G_BAD_TOK_HEADER;
        return GSS_S_DEFECTIVE_TOKEN;
     }
 
-    if (ctx->proto == 0)
+    toktype2 = load_16_be(ptr);
+
+    ptr += 2;
+    bodysize -= 2;
+
+    switch (toktype2) {
+    case KG2_TOK_MIC_MSG:
+    case KG2_TOK_WRAP_MSG:
+    case KG2_TOK_DEL_CTX:
+       code = gss_krb5int_unseal_v3_iov(context, minor_status, ctx, iov, iov_count,
+                                        conf_state, qop_state, toktype);
+       break;
+    case KG_TOK_MIC_MSG:
+    case KG_TOK_WRAP_MSG:
+    case KG_TOK_DEL_CTX:
        code = kg_unseal_v1_iov(context, minor_status, ctx, iov, iov_count,
                                (size_t)(ptr - (unsigned char *)header->buffer.value),
                                conf_state, qop_state, toktype);
-    else
-       code = gss_krb5int_unseal_v3_iov(context, minor_status, ctx, iov, iov_count,
-                                        conf_state, qop_state, toktype);
+       break;
+    default:
+       *minor_status = (OM_uint32)G_BAD_TOK_HEADER;
+       code = GSS_S_DEFECTIVE_TOKEN;
+       break;
+    }
 
     if (code != 0)
        save_error_info(*minor_status, context);
@@ -402,21 +422,19 @@ kg_unseal_stream_iov(OM_uint32 *minor_status,
                     gss_qop_t *qop_state,
                     gss_iov_buffer_desc *iov,
                     int iov_count,
-                    int toktype,
-                    int toktype2)
+                    int toktype)
 {
     unsigned char *ptr;
     unsigned int bodysize;
     OM_uint32 code = 0, major_status = GSS_S_FAILURE;
     krb5_context context = ctx->k5_context;
-    int conf_req_flag;
+    int conf_req_flag, toktype2;
     int i = 0, j;
     gss_iov_buffer_desc *tiov = NULL;
     gss_iov_buffer_t stream, data = NULL;
     gss_iov_buffer_t theader, tdata = NULL, tpadding, ttrailer;
 
     assert(toktype == KG_TOK_WRAP_MSG);
-    assert(toktype2 == KG_TOK_WRAP_MSG || toktype2 == KG2_TOK_WRAP_MSG);
 
     if (toktype != KG_TOK_WRAP_MSG || (ctx->gss_flags & GSS_C_DCE_STYLE)) {
        code = EINVAL;
@@ -429,14 +447,23 @@ kg_unseal_stream_iov(OM_uint32 *minor_status,
     ptr = (unsigned char *)stream->buffer.value;
 
     code = g_verify_token_header(ctx->mech_used,
-                                &bodysize, &ptr, toktype2,
-                                stream->buffer.length,
-                                ctx->proto ? 0 : G_VFY_TOKEN_HDR_WRAPPER_REQUIRED);
+                                &bodysize, &ptr, -1,
+                                stream->buffer.length, 0);
     if (code != 0) {
        major_status = GSS_S_DEFECTIVE_TOKEN;
        goto cleanup;
     }
 
+    if (bodysize < 2) {
+       *minor_status = (OM_uint32)G_BAD_TOK_HEADER;
+       return GSS_S_DEFECTIVE_TOKEN;
+    }
+
+    toktype2 = load_16_be(ptr);
+
+    ptr += 2;
+    bodysize -= 2;
+
     tiov = (gss_iov_buffer_desc *)calloc((size_t)iov_count + 2, sizeof(gss_iov_buffer_desc));
     if (tiov == NULL) {
        code = ENOMEM;
@@ -489,7 +516,10 @@ kg_unseal_stream_iov(OM_uint32 *minor_status,
     ttrailer = &tiov[i++];
     ttrailer->type = GSS_IOV_BUFFER_TYPE_TRAILER;
 
-    if (ctx->proto == 1) {
+    switch (toktype2) {
+    case KG2_TOK_MIC_MSG:
+    case KG2_TOK_WRAP_MSG:
+    case KG2_TOK_DEL_CTX: {
        size_t ec, rrc;
        krb5_enctype enctype = ctx->enc->enctype;
        unsigned int k5_headerlen = 0;
@@ -525,7 +555,11 @@ kg_unseal_stream_iov(OM_uint32 *minor_status,
        ttrailer->buffer.length = ec + (conf_req_flag ? 16 : 0 /* E(Header) */) + k5_trailerlen;
        ttrailer->buffer.value = (unsigned char *)stream->buffer.value +
                                 stream->buffer.length - ttrailer->buffer.length;
-    } else {
+       break;
+    }
+    case KG_TOK_MIC_MSG:
+    case KG_TOK_WRAP_MSG:
+    case KG_TOK_DEL_CTX:
        theader->buffer.length += ctx->cksum_size + kg_confounder_size(context, ctx->enc);
 
        /*
@@ -538,6 +572,13 @@ kg_unseal_stream_iov(OM_uint32 *minor_status,
        /* no TRAILER for pre-CFX */
        ttrailer->buffer.length = 0;
        ttrailer->buffer.value = NULL;
+
+       break;
+    default:
+       code = (OM_uint32)G_BAD_TOK_HEADER;
+       major_status = GSS_S_DEFECTIVE_TOKEN;
+       goto cleanup;
+       break;
     }
 
     /* IOV: -----------0-------------+---1---+--2--+----------------3--------------*/
@@ -573,7 +614,7 @@ kg_unseal_stream_iov(OM_uint32 *minor_status,
     assert(i <= iov_count + 2);
 
     major_status = kg_unseal_iov_token(&code, ctx, conf_state, qop_state,
-                                      tiov, i, toktype, toktype2);
+                                      tiov, i, toktype);
     if (major_status == GSS_S_COMPLETE)
        *data = *tdata;
     else if (tdata->type & GSS_IOV_BUFFER_FLAG_ALLOCATED) {
@@ -603,7 +644,6 @@ kg_unseal_iov(OM_uint32 *minor_status,
 {
     krb5_gss_ctx_id_rec *ctx;
     OM_uint32 code;
-    int toktype2;
 
     if (!kg_validate_ctx_id(context_handle)) {
        *minor_status = (OM_uint32)G_VALIDATE_FAILED;
@@ -616,14 +656,12 @@ kg_unseal_iov(OM_uint32 *minor_status,
        return GSS_S_NO_CONTEXT;
     }
 
-    toktype2 = kg_map_toktype(ctx->proto, toktype);
-
     if (kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_STREAM) != NULL) {
        code = kg_unseal_stream_iov(minor_status, ctx, conf_state, qop_state,
-                                   iov, iov_count, toktype, toktype2);
+                                   iov, iov_count, toktype);
     } else {
        code = kg_unseal_iov_token(minor_status, ctx, conf_state, qop_state,
-                                  iov, iov_count, toktype, toktype2);
+                                  iov, iov_count, toktype);
     }
 
     return code;
index d718ae0b18774f3c58490926371fabd88faba425..e93acb9ca29fc78cd03b714a48dc935118a8ac07 100644 (file)
 
 const char const kg_arcfour_l40[] = "fortybits";
 
+static krb5_error_code
+kg_copy_keys(krb5_context context,
+            krb5_gss_ctx_id_rec *ctx,
+            krb5_keyblock *subkey)
+{
+    krb5_error_code code;
+
+    if (ctx->enc != NULL) {
+       krb5_free_keyblock(context, ctx->enc);
+       ctx->enc = NULL;
+    }
+
+    code = krb5_copy_keyblock(context, subkey, &ctx->enc);
+    if (code != 0)
+       return code;
+
+    if (ctx->seq != NULL) {
+       krb5_free_keyblock(context, ctx->seq);
+       ctx->seq = NULL;
+    }
+
+    code = krb5_copy_keyblock(context, subkey, &ctx->seq);
+    if (code != 0)
+       return code;
+
+    return 0;
+}
+
 krb5_error_code
 kg_setup_keys(krb5_context context,
              krb5_gss_ctx_id_rec *ctx,
@@ -71,31 +99,28 @@ kg_setup_keys(krb5_context context,
 
     *cksumtype = 0;
     ctx->proto = 0;
-
-    code = krb5int_accessor(&kaccess, KRB5INT_ACCESS_VERSION);
-    if (code != 0)
-       return code;
-
-    if (ctx->enc != NULL) {
-       krb5_free_keyblock(context, ctx->enc);
-       ctx->enc = NULL;
+    if (ctx->enc == NULL) {
+        ctx->signalg = -1;
+                ctx->sealalg = -1;
     }
-    code = krb5_copy_keyblock(context, subkey, &ctx->enc);
+        
+    code = krb5int_accessor(&kaccess, KRB5INT_ACCESS_VERSION);
     if (code != 0)
        return code;
 
-    if (ctx->seq != NULL) {
-       krb5_free_keyblock(context, ctx->seq);
-       ctx->seq = NULL;
-    }
-    code = krb5_copy_keyblock(context, subkey, &ctx->seq);
+    code = (*kaccess.krb5int_c_mandatory_cksumtype)(context, subkey->enctype,
+                                                    cksumtype);
     if (code != 0)
-       return code;
+        return code;
 
     switch (subkey->enctype) {
     case ENCTYPE_DES_CBC_MD5:
     case ENCTYPE_DES_CBC_MD4:
     case ENCTYPE_DES_CBC_CRC:
+       code = kg_copy_keys(context, ctx, subkey);
+       if (code != 0)
+           return code;
+
        ctx->enc->enctype = ENCTYPE_DES_CBC_RAW;
        ctx->seq->enctype = ENCTYPE_DES_CBC_RAW;
        ctx->signalg = SGN_ALG_DES_MAC_MD5;
@@ -107,6 +132,10 @@ kg_setup_keys(krb5_context context,
            ctx->enc->contents[i] ^= 0xF0;
        break;
     case ENCTYPE_DES3_CBC_SHA1:
+       code = kg_copy_keys(context, ctx, subkey);
+       if (code != 0)
+           return code;
+
        ctx->enc->enctype = ENCTYPE_DES3_CBC_RAW;
        ctx->seq->enctype = ENCTYPE_DES3_CBC_RAW;
        ctx->signalg = SGN_ALG_HMAC_SHA1_DES3_KD;
@@ -115,19 +144,17 @@ kg_setup_keys(krb5_context context,
        break;
     case ENCTYPE_ARCFOUR_HMAC:
     case ENCTYPE_ARCFOUR_HMAC_EXP:
+       code = kg_copy_keys(context, ctx, subkey);
+       if (code != 0)
+           return code;
+
        ctx->signalg = SGN_ALG_HMAC_MD5;
        ctx->cksum_size = 8;
        ctx->sealalg = SEAL_ALG_MICROSOFT_RC4;
        break;
     default:
-       ctx->signalg = -1;
-       ctx->sealalg = -1;
        ctx->proto = 1;
 
-       code = (*kaccess.krb5int_c_mandatory_cksumtype)(context, subkey->enctype,
-                                                       cksumtype);
-       if (code != 0)
-           return code;
     }
 
     return 0;
index 7c1858553de238be9f5b1e13fa8f22dbbc7cf491..7af96403f291ddb93e30985e3a97a1949a4f5d9a 100644 (file)
@@ -556,3 +556,13 @@ chk_heimdal_seqnum(krb5_ui_4 exp_seq, krb5_ui_4 in_seq)
     else
        return 0;
 }
+
+krb5_error_code
+krb5_auth_con_get_subkey_enctype(krb5_context context,
+                                krb5_auth_context auth_context,
+                                krb5_enctype *etype)
+{
+    *etype = auth_context->negotiated_etype;
+    return 0;
+}
+
index 2e64233fd7902917cdb66ff52b2fc0ffd27ddcbe..618151100ad3dc707bf0323fa6cf8f42a3f48177 100644 (file)
@@ -427,7 +427,6 @@ krb5_rd_req_decoded_opt(krb5_context context, krb5_auth_context *auth_context,
        desired_etypes[desired_etypes_len++] = (*auth_context)->authentp->subkey->enctype;
     }
     desired_etypes[desired_etypes_len++] = req->ticket->enc_part2->session->enctype;
-    desired_etypes[desired_etypes_len++] = req->ticket->enc_part.enctype;
     desired_etypes[desired_etypes_len] = ENCTYPE_NULL;
 
     if (((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_PERMIT_ALL) == 0) {
index cdbb5984185252e3f6b487cee1f6b97e804ee7fc..1bf171a6f3451a1201d36cc24512f7ef19adf78d 100644 (file)
@@ -53,6 +53,7 @@ krb5int_accessor(krb5int_access *internals, krb5_int32 version)
 #endif
            S (free_addrlist, krb5int_free_addrlist),
            S (krb5_hmac, krb5_hmac),
+           S (krb5_auth_con_get_subkey_enctype, krb5_auth_con_get_subkey_enctype),
            S (md5_hash_provider, &krb5int_hash_md5),
            S (arcfour_enc_provider, &krb5int_enc_arcfour),
            S (sendto_udp, &krb5int_sendto),