SA-2010-007 Checksum vulnerabilities (CVE-2010-1324 and others)
authorTom Yu <tlyu@mit.edu>
Sat, 4 Dec 2010 05:11:04 +0000 (05:11 +0000)
committerTom Yu <tlyu@mit.edu>
Sat, 4 Dec 2010 05:11:04 +0000 (05:11 +0000)
Apply patch for MITKRB5-SA-2010-007.

Fix multiple checksum handling bugs, as described in:
  CVE-2010-1324
  CVE-2010-1323
  CVE-2010-4020
  CVE-2010-4021

* Return the correct (keyed) checksums as the mandatory checksum type
  for DES enctypes.
* Restrict simplified-profile checksums to their corresponding etypes.
* Add internal checks to reduce the risk of stream ciphers being used
  with simplified-profile key derivation or other algorithms relying
  on the block encryption primitive.
* Use the mandatory checksum type for the PKINIT KDC signature,
  instead of the first-listed keyed checksum.
* Use the mandatory checksum type when sending KRB-SAFE messages by
  default, instead of the first-listed keyed checksum.
* Use the mandatory checksum type for the t_kperf test program.
* Use the mandatory checksum type (without additional logic) for the
  FAST request checksum.
* Preserve the existing checksum choices (unkeyed checksums for DES
  enctypes) for the authenticator checksum, using explicit logic.
* Ensure that SAM checksums received from the KDC are keyed.
* Ensure that PAC checksums are keyed.

ticket: 6833
target_version: 1.8.4
version_fixed: 1.8.4
status: resolved

git-svn-id: svn://anonsvn.mit.edu/krb5/branches/krb5-1-8@24560 dc483132-0cff-0310-8789-dd5450dbe970

src/lib/crypto/krb/cksumtypes.c
src/lib/crypto/krb/dk/derive.c
src/lib/crypto/krb/keyed_checksum_types.c
src/lib/gssapi/krb5/util_crypt.c
src/lib/krb5/krb/mk_safe.c
src/lib/krb5/krb/pac.c
src/lib/krb5/krb/preauth2.c
src/plugins/preauth/pkinit/pkinit_srv.c

index 6e16b4ea89e803f06d5acc912e1d5dd291a5c01a..29800b7d711593de93ad349209642beb30862fc1 100644 (file)
@@ -101,7 +101,7 @@ const struct krb5_cksumtypes krb5int_cksumtypes_list[] = {
 
     { CKSUMTYPE_MD5_HMAC_ARCFOUR,
       "md5-hmac-rc4", { 0 }, "Microsoft MD5 HMAC",
-      NULL, &krb5int_hash_md5,
+      &krb5int_enc_arcfour, &krb5int_hash_md5,
       krb5int_hmacmd5_checksum, NULL,
       16, 16, 0 },
 };
index 5fd8876479982078caf79ca6a7e4f00f87f15067..221df5d7b609f84bca6b6ab6b9ebc79e37c525e5 100644 (file)
@@ -91,6 +91,8 @@ krb5int_derive_random(const struct krb5_enc_provider *enc,
     blocksize = enc->block_size;
     keybytes = enc->keybytes;
 
+    if (blocksize == 1)
+        return KRB5_BAD_ENCTYPE;
     if (inkey->keyblock.length != enc->keylength || outrnd->length != keybytes)
         return KRB5_CRYPTO_INTERNAL;
 
index 3cd1ebcae24a6e2284fbe3807852f2d8431457b2..8adef1d16facaf5079ebce8ac6f8a8bc38145b82 100644 (file)
@@ -35,6 +35,13 @@ is_keyed_for(const struct krb5_cksumtypes *ctp,
 {
     if (ctp->flags & CKSUM_UNKEYED)
         return FALSE;
+    /* Stream ciphers do not play well with RFC 3961 key derivation, so be
+     * conservative with RC4. */
+    if ((ktp->etype == ENCTYPE_ARCFOUR_HMAC ||
+         ktp->etype == ENCTYPE_ARCFOUR_HMAC_EXP) &&
+        ctp->ctype != CKSUMTYPE_HMAC_MD5_ARCFOUR &&
+        ctp->ctype != CKSUMTYPE_MD5_HMAC_ARCFOUR)
+        return FALSE;
     return (!ctp->enc || ktp->enc == ctp->enc);
 }
 
index 9699c265677200e0cc8f5879b4090cd46067c690..2cdffc8748e8d162d0a653c4c03fefa1c8c26e63 100644 (file)
@@ -119,10 +119,22 @@ kg_setup_keys(krb5_context context, krb5_gss_ctx_id_rec *ctx, krb5_key subkey,
     if (code != 0)
         return code;
 
-    code = (*kaccess.mandatory_cksumtype)(context, subkey->keyblock.enctype,
-                                          cksumtype);
-    if (code != 0)
-        return code;
+    switch (subkey->keyblock.enctype) {
+    case ENCTYPE_DES_CBC_MD4:
+        *cksumtype = CKSUMTYPE_RSA_MD4_DES;
+        break;
+    case ENCTYPE_DES_CBC_MD5:
+    case ENCTYPE_DES_CBC_CRC:
+        *cksumtype = CKSUMTYPE_RSA_MD5_DES;
+        break;
+    default:
+        code = (*kaccess.mandatory_cksumtype)(context,
+                                              subkey->keyblock.enctype,
+                                              cksumtype);
+        if (code != 0)
+            return code;
+        break;
+    }
 
     switch (subkey->keyblock.enctype) {
     case ENCTYPE_DES_CBC_MD5:
index eaa3add8288330eb929e7a2d4761c824622dcd89..2c790b7cf9bd2c71f93712ba4975f250e2bbea03 100644 (file)
@@ -215,10 +215,28 @@ krb5_mk_safe(krb5_context context, krb5_auth_context auth_context,
             for (i = 0; i < nsumtypes; i++)
                 if (auth_context->safe_cksumtype == sumtypes[i])
                     break;
-            if (i == nsumtypes)
-                i = 0;
-            sumtype = sumtypes[i];
             krb5_free_cksumtypes (context, sumtypes);
+            if (i < nsumtypes)
+                sumtype = auth_context->safe_cksumtype;
+            else {
+                switch (enctype) {
+                case ENCTYPE_DES_CBC_MD4:
+                    sumtype = CKSUMTYPE_RSA_MD4_DES;
+                    break;
+                case ENCTYPE_DES_CBC_MD5:
+                case ENCTYPE_DES_CBC_CRC:
+                    sumtype = CKSUMTYPE_RSA_MD5_DES;
+                    break;
+                default:
+                    retval = krb5int_c_mandatory_cksumtype(context, enctype,
+                                                           &sumtype);
+                    if (retval) {
+                        CLEANUP_DONE();
+                        goto error;
+                    }
+                    break;
+                }
+            }
         }
         if ((retval = krb5_mk_safe_basic(context, userdata, key, &replaydata,
                                          plocal_fulladdr, premote_fulladdr,
index cda09b25558566bad9e5aae61a96f1cdc404e88e..abec59b028cb70fb74159eaa6c4fcb85efa55590 100644 (file)
@@ -582,6 +582,8 @@ k5_pac_verify_server_checksum(krb5_context context,
     checksum.checksum_type = load_32_le(p);
     checksum.length = checksum_data.length - PAC_SIGNATURE_DATA_LENGTH;
     checksum.contents = p + PAC_SIGNATURE_DATA_LENGTH;
+    if (!krb5_c_is_keyed_cksum(checksum.checksum_type))
+        return KRB5KRB_AP_ERR_INAPP_CKSUM;
 
     pac_data.length = pac->data.length;
     pac_data.data = malloc(pac->data.length);
index cf99a29b1dcdfec11e0c59854d9e0c0013dcdc3d..2776b19e991ad53e2253b3fa1bcc581c87368e02 100644 (file)
@@ -1578,7 +1578,9 @@ pa_sam_2(krb5_context context, krb5_kdc_req *request, krb5_pa_data *in_padata,
 
     cksum = sc2->sam_cksum;
 
-    while (*cksum) {
+    for (; *cksum; cksum++) {
+        if (!krb5_c_is_keyed_cksum((*cksum)->checksum_type))
+            continue;
         /* Check this cksum */
         retval = krb5_c_verify_checksum(context, as_key,
                                         KRB5_KEYUSAGE_PA_SAM_CHALLENGE_CKSUM,
@@ -1592,7 +1594,6 @@ pa_sam_2(krb5_context context, krb5_kdc_req *request, krb5_pa_data *in_padata,
         }
         if (valid_cksum)
             break;
-        cksum++;
     }
 
     if (!valid_cksum) {
index 719b01c80c04142bc5a49c7a0c4650a2925c7694..db38bcc544c39b61133788f3b65eb6b56ce4df9f 100644 (file)
@@ -691,8 +691,7 @@ pkinit_server_return_padata(krb5_context context,
     krb5_reply_key_pack *key_pack = NULL;
     krb5_reply_key_pack_draft9 *key_pack9 = NULL;
     krb5_data *encoded_key_pack = NULL;
-    unsigned int num_types;
-    krb5_cksumtype *cksum_types = NULL;
+    krb5_cksumtype cksum_type;
 
     pkinit_kdc_context plgctx;
     pkinit_kdc_req_context reqctx;
@@ -882,14 +881,25 @@ pkinit_server_return_padata(krb5_context context,
                 retval = ENOMEM;
                 goto cleanup;
             }
-            /* retrieve checksums for a given enctype of the reply key */
-            retval = krb5_c_keyed_checksum_types(context,
-                                                 encrypting_key->enctype, &num_types, &cksum_types);
-            if (retval)
-                goto cleanup;
 
-            /* pick the first of acceptable enctypes for the checksum */
-            retval = krb5_c_make_checksum(context, cksum_types[0],
+            switch (encrypting_key->enctype) {
+            case ENCTYPE_DES_CBC_MD4:
+                cksum_type = CKSUMTYPE_RSA_MD4_DES;
+                break;
+            case ENCTYPE_DES_CBC_MD5:
+            case ENCTYPE_DES_CBC_CRC:
+                cksum_type = CKSUMTYPE_RSA_MD5_DES;
+                break;
+            default:
+                retval = krb5int_c_mandatory_cksumtype(context,
+                                                       encrypting_key->enctype,
+                                                       &cksum_type);
+                if (retval)
+                    goto cleanup;
+                break;
+            }
+
+            retval = krb5_c_make_checksum(context, cksum_type,
                                           encrypting_key, KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM,
                                           req_pkt, &key_pack->asChecksum);
             if (retval) {
@@ -1033,7 +1043,6 @@ cleanup:
         krb5_free_data(context, encoded_key_pack);
     free(dh_pubkey);
     free(server_key);
-    free(cksum_types);
 
     switch ((int)padata->pa_type) {
     case KRB5_PADATA_PK_AS_REQ: