Save encoded KRB-SAFE-BODY to avoid problems caused by re-encoding it.
authorTom Yu <tlyu@mit.edu>
Wed, 8 Oct 2003 23:53:23 +0000 (23:53 +0000)
committerTom Yu <tlyu@mit.edu>
Wed, 8 Oct 2003 23:53:23 +0000 (23:53 +0000)
Also, handle correctly implemented RFC 1510 KRB-SAFE i.e., checksummed
over KRB-SAFE-BODY only.

ticket: 1893
tags: pullup

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

src/include/ChangeLog
src/include/k5-int.h
src/lib/krb5/asn.1/ChangeLog
src/lib/krb5/asn.1/asn1_k_encode.c
src/lib/krb5/asn.1/asn1_k_encode.h
src/lib/krb5/asn.1/krb5_decode.c
src/lib/krb5/asn.1/krb5_encode.c
src/lib/krb5/krb/ChangeLog
src/lib/krb5/krb/rd_safe.c

index 0b0ed7d990a2bb612ee111e75b2de929b2bbd42a..84602683f78d210cd0bf87624a66bbd27dceec5e 100644 (file)
@@ -1,3 +1,8 @@
+2003-10-08  Tom Yu  <tlyu@mit.edu>
+
+       * k5-int.h: Add prototypes for decode_krb5_safe_with_body and
+       encode_krb5_safe_with_body.
+
 2003-09-26  Ken Raeburn  <raeburn@mit.edu>
 
        * Makefile.in ($(srcdir)/krb5/autoconf.h.in): Depend on
index 0cb1aeecb7ac35c4f63e34ce503612d4972aa770..ebcd2135f16ba75b2b950dd4c877155f7bb7dd58 100644 (file)
@@ -1221,6 +1221,9 @@ krb5_error_code encode_krb5_kdc_req_body
 krb5_error_code encode_krb5_safe
        (const krb5_safe *rep, krb5_data **code);
 
+krb5_error_code encode_krb5_safe_with_body
+       (const krb5_safe *rep, const krb5_data *body, krb5_data **code);
+
 krb5_error_code encode_krb5_priv
        (const krb5_priv *rep, krb5_data **code);
 
@@ -1400,6 +1403,9 @@ krb5_error_code decode_krb5_kdc_req_body
 krb5_error_code decode_krb5_safe
        (const krb5_data *output, krb5_safe **rep);
 
+krb5_error_code decode_krb5_safe_with_body
+       (const krb5_data *output, krb5_safe **rep, krb5_data *body);
+
 krb5_error_code decode_krb5_priv
        (const krb5_data *output, krb5_priv **rep);
 
index 578352bdb0dc34610f235b7e3167dc589ae5750b..520999d7fc4cc613d09b507cf0423256a4a57053 100644 (file)
@@ -1,3 +1,19 @@
+2003-10-08  Tom Yu  <tlyu@mit.edu>
+
+       * asn1_k_encode.c (asn1_encode_krb_saved_safe_body): New function;
+       kludge to insert a raw pre-encoded KRB-SAFE-BODY.
+
+       * asn1_k_encode.h (asn1_encode_krb_saved_safe_body): Add
+       prototype.
+
+       * krb5_decode.c (decode_krb5_safe_with_body): New function; saves
+       a copy of the encoding of the KRB-SAFE-BODY to avoid problems
+       caused by re-encoding it during verification.
+
+       * krb5_encode.c (encode_krb5_safe_with_body): New function;
+       re-encode a KRB-SAFE using a saved KRB-SAFE-BODY encoding, to
+       avoid trouble with re-encoding a KRB-SAFE-BODY.
+
 2003-07-22  Sam Hartman  <hartmans@avalanche-breakdown.mit.edu>
 
        * asn1_k_decode.c (asn1_decode_etype_info2_entry_1_3): Decoder for
index 325a6ce775f5dac62ec16c0caa524e2c89afca20..00cfab0322f9a6a8b69fb38f1e80fcf7fcfef80d 100644 (file)
@@ -942,3 +942,20 @@ asn1_error_code asn1_encode_predicted_sam_response(asn1buf *buf, const krb5_pred
 
   asn1_cleanup();
 }
+
+/*
+ * Do some ugliness to insert a raw pre-encoded KRB-SAFE-BODY.
+ */
+asn1_error_code asn1_encode_krb_saved_safe_body(asn1buf *buf, const krb5_data *body, unsigned int *retlen)
+{
+  asn1_error_code retval;
+
+  retval = asn1buf_insert_octetstring(buf, body->length,
+                                     (krb5_octet *)body->data);
+  if (retval){
+    asn1buf_destroy(&buf);
+    return retval; 
+  }
+  *retlen = body->length;
+  return 0;
+}
index a2429a77886e815634ab29dd64df908999656f8e..caa46c570cb98a0c7e1cc65264d4431452593393 100644 (file)
@@ -266,4 +266,7 @@ asn1_error_code asn1_encode_predicted_sam_response
        (asn1buf *buf, const krb5_predicted_sam_response *val, 
                   unsigned int *retlen);
 
+asn1_error_code asn1_encode_krb_saved_safe_body
+       (asn1buf *buf, const krb5_data *body, unsigned int *retlen);
+
 #endif
index 4172c882bf9429679af6c9609868ca7e06293c4e..596997fe953ff060bc2cef3bd3273912ac7b70bf 100644 (file)
@@ -90,6 +90,7 @@ if((var) == NULL) clean_return(ENOMEM)
   construction = t2.construction;              \
   tagnum = t2.tagnum;                          \
   indef = t2.indef;                            \
+  taglen = t2.length;                          \
 }
 
 #define get_eoc()                                              \
@@ -107,6 +108,7 @@ if((var) == NULL) clean_return(ENOMEM)
 
 /* decode sequence header and initialize tagnum with the first field */
 #define begin_structure()\
+unsigned int taglen;\
 asn1buf subbuf;\
 int seqindef;\
 int indef;\
@@ -494,8 +496,26 @@ krb5_error_code decode_krb5_kdc_req_body(const krb5_data *code, krb5_kdc_req **r
   cleanup(free);
 }
 
-krb5_error_code decode_krb5_safe(const krb5_data *code, krb5_safe **rep)
+/*
+ * decode_krb5_safe_with_body
+ *
+ * Like decode_krb5_safe(), but grabs the encoding of the
+ * KRB-SAFE-BODY as well, in case re-encoding would produce a
+ * different encoding.  (Yes, we're using DER, but there's this
+ * annoying problem with pre-1.3.x code using signed sequence numbers,
+ * which we permissively decode and cram into unsigned 32-bit numbers.
+ * When they're re-encoded, they're no longer negative if they started
+ * out negative, so checksum verification fails.)
+ *
+ * This does *not* perform any copying; the returned pointer to the
+ * encoded KRB-SAFE-BODY points into the input buffer.
+ */
+krb5_error_code decode_krb5_safe_with_body(
+  const krb5_data *code,
+  krb5_safe **rep,
+  krb5_data *body)
 {
+  krb5_data tmpbody;
   setup();
   alloc_field(*rep,krb5_safe);
   clear_field(rep,checksum);
@@ -511,12 +531,26 @@ krb5_error_code decode_krb5_safe(const krb5_data *code, krb5_safe **rep)
       if(msg_type != KRB5_SAFE) clean_return(KRB5_BADMSGTYPE);
 #endif
     }
+    /*
+     * Gross kludge to extract pointer to encoded safe-body.  Relies
+     * on tag prefetch done by next_tag().  Don't handle indefinite
+     * encoding, as it's too much work.
+     */
+    if (!indef) {
+      tmpbody.length = taglen;
+      tmpbody.data = subbuf.next;
+    } else {
+      tmpbody.length = 0;
+      tmpbody.data = NULL;
+    }
     get_field(**rep,2,asn1_decode_krb_safe_body);
     alloc_field((*rep)->checksum,krb5_checksum);
     get_field(*((*rep)->checksum),3,asn1_decode_checksum);
   (*rep)->magic = KV5M_SAFE;
     end_structure();
   }
+  if (body != NULL)
+    *body = tmpbody;
   cleanup_manual();
 error_out:
   if (rep && *rep) {
@@ -526,6 +560,11 @@ error_out:
   return retval;
 }
 
+krb5_error_code decode_krb5_safe(const krb5_data *code, krb5_safe **rep)
+{
+  return decode_krb5_safe_with_body(code, rep, NULL);
+}
+
 krb5_error_code decode_krb5_priv(const krb5_data *code, krb5_priv **rep)
 {
   setup();
index eed6faf451563d2642f26d9829ddcbbb5bbdab7a..ecdfa18787a3a883de1089337a1cc8f31ae88796 100644 (file)
@@ -478,6 +478,43 @@ krb5_error_code encode_krb5_safe(const krb5_safe *rep, krb5_data **code)
   krb5_cleanup();
 }
 
+/*
+ * encode_krb5_safe_with_body
+ *
+ * Like encode_krb5_safe(), except takes a saved KRB-SAFE-BODY
+ * encoding to avoid problems with re-encoding.
+ */
+krb5_error_code encode_krb5_safe_with_body(
+  const krb5_safe *rep,
+  const krb5_data *body,
+  krb5_data **code)
+{
+  krb5_setup();
+
+  if (body == NULL) {
+      asn1buf_destroy(&buf);
+      return ASN1_MISSING_FIELD;
+  }
+
+  /* cksum[3]          Checksum */
+  krb5_addfield(rep->checksum,3,asn1_encode_checksum);
+
+  /* safe-body[2]      KRB-SAFE-BODY */
+  krb5_addfield(body,2,asn1_encode_krb_saved_safe_body);
+
+  /* msg-type[1]       INTEGER */
+  krb5_addfield(ASN1_KRB_SAFE,1,asn1_encode_integer);
+
+  /* pvno[0]           INTEGER */
+  krb5_addfield(KVNO,0,asn1_encode_integer);
+
+  /* KRB-SAFE ::= [APPLICATION 20] SEQUENCE */
+  krb5_makeseq();
+  krb5_apptag(20);
+
+  krb5_cleanup();
+}
+
 krb5_error_code encode_krb5_priv(const krb5_priv *rep, krb5_data **code)
 {
   krb5_setup();
index 5d777909a6bdde88caf655ac5454e7b5c7975693..57d63bfd7c4eee272774f81c7c15cd5b52a5c027 100644 (file)
@@ -1,3 +1,10 @@
+2003-10-08  Tom Yu  <tlyu@mit.edu>
+
+       * rd_safe.c (krb5_rd_safe_basic): Save the encoded KRB-SAFE-BODY
+       to avoid trouble caused by re-encoding.  Also, handle correctly
+       implemented RFC 1510 KRB-SAFE, i.e., checksummed over
+       KRB-SAFE-BODY only.
+
 2003-09-02  Tom Yu  <tlyu@mit.edu>
 
        * conv_creds.c (krb524_convert_creds_plain): Apply patch from
index 41c2596b7aba5f86182aaac67498e8324a6c9f98..15dc6dcccd6923fad9831826e567f6c4f6a72cb5 100644 (file)
@@ -51,6 +51,7 @@ krb5_rd_safe_basic(krb5_context context, const krb5_data *inbuf, const krb5_keyb
 {
     krb5_error_code      retval;
     krb5_safe          * message;
+    krb5_data safe_body;
     krb5_checksum our_cksum, *his_cksum;
     krb5_octet zero_octet = 0;
     krb5_data *scratch;
@@ -59,7 +60,7 @@ krb5_rd_safe_basic(krb5_context context, const krb5_data *inbuf, const krb5_keyb
     if (!krb5_is_krb_safe(inbuf))
        return KRB5KRB_AP_ERR_MSG_TYPE;
 
-    if ((retval = decode_krb5_safe(inbuf, &message)))
+    if ((retval = decode_krb5_safe_with_body(inbuf, &message, &safe_body)))
        return retval;
 
     if (!krb5_c_valid_cksumtype(message->checksum->checksum_type)) {
@@ -113,7 +114,7 @@ krb5_rd_safe_basic(krb5_context context, const krb5_data *inbuf, const krb5_keyb
 
     message->checksum = &our_cksum;
 
-    if ((retval = encode_krb5_safe(message, &scratch)))
+    if ((retval = encode_krb5_safe_with_body(message, &safe_body, &scratch)))
        goto cleanup;
 
     message->checksum = his_cksum;
@@ -126,8 +127,17 @@ krb5_rd_safe_basic(krb5_context context, const krb5_data *inbuf, const krb5_keyb
     krb5_free_data(context, scratch);
     
     if (!valid) {
-       retval = KRB5KRB_AP_ERR_MODIFIED;
-       goto cleanup;
+       /*
+        * Checksum over only the KRB-SAFE-BODY, like RFC 1510 says, in
+        * case someone actually implements it correctly.
+        */
+       retval = krb5_c_verify_checksum(context, keyblock,
+                                       KRB5_KEYUSAGE_KRB_SAFE_CKSUM,
+                                       &safe_body, his_cksum, &valid);
+       if (!valid) {
+           retval = KRB5KRB_AP_ERR_MODIFIED;
+           goto cleanup;
+       }
     }
 
     replaydata->timestamp = message->timestamp;