The payloads are layered like onions, so you can validate one layer and
authorpatrick <patrick@openbsd.org>
Mon, 4 Dec 2017 16:52:16 +0000 (16:52 +0000)
committerpatrick <patrick@openbsd.org>
Mon, 4 Dec 2017 16:52:16 +0000 (16:52 +0000)
then call the next one, which can then validate itself.  Thing is, most
layers try to run validations on the upper layer, which is not useful
and rather confusing.  This cleans it up.

First change is that the generic payload parser does not anymore pass
the length of the whole datagram, including all remaining payloads, but
passes only the length of the specific payload to the specific payload
parser.  Second change is that the payload validators don't check the
length of the upper layer, but only verify their own lengths.

Diff discussed with hshoexer@ and sthen@
Tested by sthen@

sbin/iked/ikev2_pld.c

index 63b6d0a..07efd45 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ikev2_pld.c,v 1.64 2017/11/30 12:18:44 patrick Exp $  */
+/*     $OpenBSD: ikev2_pld.c,v 1.65 2017/12/04 16:52:16 patrick Exp $  */
 
 /*
  * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -48,7 +48,7 @@ int    ikev2_validate_pld(struct iked_message *, size_t, size_t,
 int     ikev2_pld_payloads(struct iked *, struct iked_message *,
            size_t, size_t, unsigned int);
 int     ikev2_validate_sa(struct iked_message *, size_t, size_t,
-           struct ikev2_payload *, struct ikev2_sa_proposal *);
+           struct ikev2_sa_proposal *);
 int     ikev2_pld_sa(struct iked *, struct ikev2_payload *,
            struct iked_message *, size_t, size_t);
 int     ikev2_validate_xform(struct iked_message *, size_t, size_t,
@@ -60,49 +60,47 @@ int  ikev2_validate_attr(struct iked_message *, size_t, size_t,
 int     ikev2_pld_attr(struct iked *, struct ikev2_transform *,
            struct iked_message *, size_t, size_t);
 int     ikev2_validate_ke(struct iked_message *, size_t, size_t,
-           struct ikev2_payload *, struct ikev2_keyexchange *);
+           struct ikev2_keyexchange *);
 int     ikev2_pld_ke(struct iked *, struct ikev2_payload *,
            struct iked_message *, size_t, size_t);
 int     ikev2_validate_id(struct iked_message *, size_t, size_t,
-           struct ikev2_payload *, struct ikev2_id *);
+           struct ikev2_id *);
 int     ikev2_pld_id(struct iked *, struct ikev2_payload *,
            struct iked_message *, size_t, size_t, unsigned int);
 int     ikev2_validate_cert(struct iked_message *, size_t, size_t,
-           struct ikev2_payload *, struct ikev2_cert *);
+           struct ikev2_cert *);
 int     ikev2_pld_cert(struct iked *, struct ikev2_payload *,
            struct iked_message *, size_t, size_t);
 int     ikev2_validate_certreq(struct iked_message *, size_t, size_t,
-           struct ikev2_payload *, struct ikev2_cert *);
+           struct ikev2_cert *);
 int     ikev2_pld_certreq(struct iked *, struct ikev2_payload *,
            struct iked_message *, size_t, size_t);
-int     ikev2_validate_nonce(struct iked_message *, size_t, size_t,
-           struct ikev2_payload *);
 int     ikev2_pld_nonce(struct iked *, struct ikev2_payload *,
            struct iked_message *, size_t, size_t);
 int     ikev2_validate_notify(struct iked_message *, size_t, size_t,
-           struct ikev2_payload *, struct ikev2_notify *);
+           struct ikev2_notify *);
 int     ikev2_pld_notify(struct iked *, struct ikev2_payload *,
            struct iked_message *, size_t, size_t);
 int     ikev2_validate_delete(struct iked_message *, size_t, size_t,
-           struct ikev2_payload *, struct ikev2_delete *);
+           struct ikev2_delete *);
 int     ikev2_pld_delete(struct iked *, struct ikev2_payload *,
            struct iked_message *, size_t, size_t);
 int     ikev2_validate_ts(struct iked_message *, size_t, size_t,
-           struct ikev2_payload *, struct ikev2_tsp *);
+           struct ikev2_tsp *);
 int     ikev2_pld_ts(struct iked *, struct ikev2_payload *,
            struct iked_message *, size_t, size_t, unsigned int);
 int     ikev2_validate_auth(struct iked_message *, size_t, size_t,
-           struct ikev2_payload *, struct ikev2_auth *);
+           struct ikev2_auth *);
 int     ikev2_pld_auth(struct iked *, struct ikev2_payload *,
            struct iked_message *, size_t, size_t);
 int     ikev2_pld_e(struct iked *, struct ikev2_payload *,
-           struct iked_message *, size_t);
+           struct iked_message *, size_t, size_t);
 int     ikev2_validate_cp(struct iked_message *, size_t, size_t,
-           struct ikev2_payload *, struct ikev2_cp *);
+           struct ikev2_cp *);
 int     ikev2_pld_cp(struct iked *, struct ikev2_payload *,
            struct iked_message *, size_t, size_t);
 int     ikev2_validate_eap(struct iked_message *, size_t, size_t,
-           struct ikev2_payload *, struct eap_header *);
+           struct eap_header *);
 int     ikev2_pld_eap(struct iked *, struct ikev2_payload *,
            struct iked_message *, size_t, size_t);
 
@@ -182,16 +180,16 @@ ikev2_pld_payloads(struct iked *env, struct iked_message *msg,
        unsigned int             e;
        int                      ret;
        uint8_t                 *msgbuf = ibuf_data(msg->msg_data);
-       size_t                   left;
+       size_t                   total, left;
 
        /* Check if message was decrypted in an E payload */
        e = msg->msg_e ? IKED_E : 0;
 
-       while (payload != 0 && offset < length) {
-               /* Bytes left in datagram. */
-               left = length - offset;
+       /* Bytes left in datagram. */
+       total = length - offset;
 
-               if (ikev2_validate_pld(msg, offset, left, &pld))
+       while (payload != 0 && offset < length) {
+               if (ikev2_validate_pld(msg, offset, total, &pld))
                        return (-1);
 
                log_debug("%s: %spayload %s"
@@ -204,7 +202,8 @@ ikev2_pld_payloads(struct iked *env, struct iked_message *msg,
 
                /* Skip over generic payload header. */
                offset += sizeof(pld);
-               left -= sizeof(pld);
+               total -= sizeof(pld);
+               left = betoh16(pld.pld_length) - sizeof(pld);
                ret = 0;
 
                switch (payload | e) {
@@ -248,7 +247,7 @@ ikev2_pld_payloads(struct iked *env, struct iked_message *msg,
                            payload);
                        break;
                case IKEV2_PAYLOAD_SK:
-                       ret = ikev2_pld_e(env, &pld, msg, offset);
+                       ret = ikev2_pld_e(env, &pld, msg, offset, left);
                        break;
                case IKEV2_PAYLOAD_CP | IKED_E:
                        ret = ikev2_pld_cp(env, &pld, msg, offset, left);
@@ -272,7 +271,8 @@ ikev2_pld_payloads(struct iked *env, struct iked_message *msg,
                        return (0);
 
                payload = pld.pld_nextpayload;
-               offset += betoh16(pld.pld_length) - sizeof(pld);
+               offset += left;
+               total -= left;
        }
 
        return (0);
@@ -280,20 +280,11 @@ ikev2_pld_payloads(struct iked *env, struct iked_message *msg,
 
 int
 ikev2_validate_sa(struct iked_message *msg, size_t offset, size_t left,
-    struct ikev2_payload *pld, struct ikev2_sa_proposal *sap)
+    struct ikev2_sa_proposal *sap)
 {
        uint8_t         *msgbuf = ibuf_data(msg->msg_data);
-       size_t           pld_length, sap_length;
+       size_t           sap_length;
 
-       pld_length = betoh16(pld->pld_length);
-       if (pld_length < sizeof(*pld) + sizeof(*sap)) {
-               log_debug("%s: malformed payload: specified length smaller "
-                   "than minimum size (%zu < %zu)", __func__, pld_length,
-                   sizeof(*pld) + sizeof(*sap));
-               return (-1);
-       }
-
-       /* This will actually be caught by earlier checks. */
        if (left < sizeof(*sap)) {
                log_debug("%s: malformed payload: too short for header "
                    "(%zu < %zu)", __func__, left, sizeof(*sap));
@@ -316,30 +307,30 @@ ikev2_validate_sa(struct iked_message *msg, size_t offset, size_t left,
         * NB: There might be more proposals, we parse only the first one.
         * This condition must never be true.
         */
-       if (pld_length - sizeof(*pld) < sap_length) {
+       if (left < sap_length) {
                log_debug("%s: payload malformed: SA payload length mismatches "
                    "proposal substructure length (%lu < %zu)", __func__,
-                   pld_length - sizeof(*pld), sap_length);
+                   left, sap_length);
                return (-1);
        }
        /*
         * If there is only one proposal, sap_length must be the
         * total payload size.
         */
-       if (!sap->sap_more && ((pld_length - sizeof(*pld)) != sap_length)) {
+       if (!sap->sap_more && left != sap_length) {
                log_debug("%s: payload malformed: SA payload length mismatches "
                    "single proposal substructure length (%lu != %zu)",
-                   __func__, pld_length - sizeof(*pld), sap_length);
+                   __func__, left, sap_length);
                return (-1);
        }
        /*
         * If there are more than one proposal, there must be bytes
         * left in the payload.
         */
-       if (sap->sap_more && ((pld_length - sizeof(*pld)) <= sap_length)) {
+       if (sap->sap_more && left <= sap_length) {
                log_debug("%s: payload malformed: SA payload too small for "
                    "further proposals (%zu <= %zu)", __func__,
-                   pld_length - sizeof(*pld), sap_length);
+                   left, sap_length);
                return (-1);
        }
        return (0);
@@ -361,7 +352,7 @@ ikev2_pld_sa(struct iked *env, struct ikev2_payload *pld,
        struct iked_proposals           *props;
        size_t                           total;
 
-       if (ikev2_validate_sa(msg, offset, left, pld, &sap))
+       if (ikev2_validate_sa(msg, offset, left, &sap))
                return (-1);
 
        if (sap.sap_more)
@@ -641,20 +632,10 @@ ikev2_pld_attr(struct iked *env, struct ikev2_transform *xfrm,
 
 int
 ikev2_validate_ke(struct iked_message *msg, size_t offset, size_t left,
-    struct ikev2_payload *pld, struct ikev2_keyexchange *kex)
+    struct ikev2_keyexchange *kex)
 {
        uint8_t         *msgbuf = ibuf_data(msg->msg_data);
-       size_t           pld_length;
 
-       pld_length = betoh16(pld->pld_length);
-       if (pld_length < sizeof(*pld) + sizeof(*kex)) {
-               log_debug("%s: malformed payload: specified length smaller "
-                   "than minimum size (%zu < %zu)", __func__, pld_length,
-                   sizeof(*pld) + sizeof(*kex));
-               return (-1);
-       }
-
-       /* This will actually be caught by earlier checks. */
        if (left < sizeof(*kex)) {
                log_debug("%s: malformed payload: too short for header "
                    "(%zu < %zu)", __func__, left, sizeof(*kex));
@@ -674,7 +655,7 @@ ikev2_pld_ke(struct iked *env, struct ikev2_payload *pld,
        size_t                           len;
        uint8_t                         *msgbuf = ibuf_data(msg->msg_data);
 
-       if (ikev2_validate_ke(msg, offset, left, pld, &kex))
+       if (ikev2_validate_ke(msg, offset, left, &kex))
                return (-1);
 
        log_debug("%s: dh group %s reserved %d", __func__,
@@ -682,18 +663,12 @@ ikev2_pld_ke(struct iked *env, struct ikev2_payload *pld,
            betoh16(kex.kex_reserved));
 
        buf = msgbuf + offset + sizeof(kex);
-       len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(kex);
+       len = left - sizeof(kex);
 
        if (len == 0) {
                log_debug("%s: malformed payload: no KE data given", __func__);
                return (-1);
        }
-       /* This will actually be caught by earlier checks. */
-       if (left < len) {
-               log_debug("%s: malformed payload: smaller than specified "
-                    "(%zu < %zu)", __func__, left, len);
-               return (-1);
-       }
 
        print_hex(buf, 0, len);
 
@@ -711,20 +686,10 @@ ikev2_pld_ke(struct iked *env, struct ikev2_payload *pld,
 
 int
 ikev2_validate_id(struct iked_message *msg, size_t offset, size_t left,
-    struct ikev2_payload *pld, struct ikev2_id *id)
+    struct ikev2_id *id)
 {
        uint8_t         *msgbuf = ibuf_data(msg->msg_data);
-       size_t           pld_length;
-
-       pld_length = betoh16(pld->pld_length);
-       if (pld_length < sizeof(*pld) + sizeof(*id)) {
-               log_debug("%s: malformed payload: specified length smaller "
-                   "than minimum size (%zu < %zu)", __func__, pld_length,
-                   sizeof(*pld) + sizeof(*id));
-               return (-1);
-       }
 
-       /* This will actually be caught by earlier checks. */
        if (left < sizeof(*id)) {
                log_debug("%s: malformed payload: too short for header "
                    "(%zu < %zu)", __func__, left, sizeof(*id));
@@ -747,14 +712,14 @@ ikev2_pld_id(struct iked *env, struct ikev2_payload *pld,
        uint8_t                         *msgbuf = ibuf_data(msg->msg_data);
        char                             idstr[IKED_ID_SIZE];
 
-       if (ikev2_validate_id(msg, offset, left, pld, &id))
+       if (ikev2_validate_id(msg, offset, left, &id))
                return (-1);
 
        bzero(&idb, sizeof(idb));
 
        /* Don't strip the Id payload header */
        ptr = msgbuf + offset;
-       len = betoh16(pld->pld_length) - sizeof(*pld);
+       len = left;
 
        idb.id_type = id.id_type;
        idb.id_offset = sizeof(id);
@@ -794,20 +759,10 @@ ikev2_pld_id(struct iked *env, struct ikev2_payload *pld,
 
 int
 ikev2_validate_cert(struct iked_message *msg, size_t offset, size_t left,
-    struct ikev2_payload *pld, struct ikev2_cert *cert)
+    struct ikev2_cert *cert)
 {
        uint8_t         *msgbuf = ibuf_data(msg->msg_data);
-       size_t           pld_length;
-
-       pld_length = betoh16(pld->pld_length);
-       if (pld_length < sizeof(*pld) + sizeof(*cert)) {
-               log_debug("%s: malformed payload: specified length smaller "
-                   "than minimum size (%zu < %zu)", __func__, pld_length,
-                   sizeof(*pld) + sizeof(*cert));
-               return (-1);
-       }
 
-       /* This will actually be caught by earlier checks. */
        if (left < sizeof(*cert)) {
                log_debug("%s: malformed payload: too short for header "
                    "(%zu < %zu)", __func__, left, sizeof(*cert));
@@ -828,12 +783,12 @@ ikev2_pld_cert(struct iked *env, struct ikev2_payload *pld,
        struct iked_id                  *certid;
        uint8_t                         *msgbuf = ibuf_data(msg->msg_data);
 
-       if (ikev2_validate_cert(msg, offset, left, pld, &cert))
+       if (ikev2_validate_cert(msg, offset, left, &cert))
                return (-1);
        offset += sizeof(cert);
 
        buf = msgbuf + offset;
-       len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(cert);
+       len = left - sizeof(cert);
 
        log_debug("%s: type %s length %zu",
            __func__, print_map(cert.cert_type, ikev2_cert_map), len);
@@ -861,20 +816,10 @@ ikev2_pld_cert(struct iked *env, struct ikev2_payload *pld,
 
 int
 ikev2_validate_certreq(struct iked_message *msg, size_t offset, size_t left,
-    struct ikev2_payload *pld, struct ikev2_cert *cert)
+    struct ikev2_cert *cert)
 {
        uint8_t         *msgbuf = ibuf_data(msg->msg_data);
-       size_t           pld_length;
 
-       pld_length = betoh16(pld->pld_length);
-       if (pld_length < sizeof(*pld) + sizeof(*cert)) {
-               log_debug("%s: malformed payload: specified length smaller "
-                   "than minimum size (%zu < %zu)", __func__, pld_length,
-                   sizeof(*pld) + sizeof(*cert));
-               return (-1);
-       }
-
-       /* This will actually be caught by earlier checks. */
        if (left < sizeof(*cert)) {
                log_debug("%s: malformed payload: too short for header "
                    "(%zu < %zu)", __func__, left, sizeof(*cert));
@@ -895,22 +840,16 @@ ikev2_pld_certreq(struct iked *env, struct ikev2_payload *pld,
        ssize_t                          len;
        uint8_t                         *msgbuf = ibuf_data(msg->msg_data);
 
-       if (ikev2_validate_certreq(msg, offset, left, pld, &cert))
+       if (ikev2_validate_certreq(msg, offset, left, &cert))
                return (-1);
        offset += sizeof(cert);
 
        buf = msgbuf + offset;
-       len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(cert);
+       len = left - sizeof(cert);
 
        log_debug("%s: type %s length %zd",
            __func__, print_map(cert.cert_type, ikev2_cert_map), len);
 
-       /* This will actually be caught by earlier checks. */
-       if (len < 0) {
-               log_debug("%s: invalid certificate request length", __func__);
-               return (-1);
-       }
-
        print_hex(buf, 0, len);
 
        if (!ikev2_msg_frompeer(msg))
@@ -942,20 +881,10 @@ ikev2_pld_certreq(struct iked *env, struct ikev2_payload *pld,
 
 int
 ikev2_validate_auth(struct iked_message *msg, size_t offset, size_t left,
-    struct ikev2_payload *pld, struct ikev2_auth *auth)
+    struct ikev2_auth *auth)
 {
        uint8_t         *msgbuf = ibuf_data(msg->msg_data);
-       size_t           pld_length;
-
-       pld_length = betoh16(pld->pld_length);
-       if (pld_length < sizeof(*pld) + sizeof(*auth)) {
-               log_debug("%s: malformed payload: specified length smaller "
-                   "than minimum size (%zu < %zu)", __func__, pld_length,
-                   sizeof(*pld) + sizeof(*auth));
-               return (-1);
-       }
 
-       /* This will actually be caught by earlier checks. */
        if (left < sizeof(*auth)) {
                log_debug("%s: malformed payload: too short for header "
                    "(%zu < %zu)", __func__, left, sizeof(*auth));
@@ -977,12 +906,12 @@ ikev2_pld_auth(struct iked *env, struct ikev2_payload *pld,
        struct iked_sa                  *sa = msg->msg_sa;
        uint8_t                         *msgbuf = ibuf_data(msg->msg_data);
 
-       if (ikev2_validate_auth(msg, offset, left, pld, &auth))
+       if (ikev2_validate_auth(msg, offset, left, &auth))
                return (-1);
        offset += sizeof(auth);
 
        buf = msgbuf + offset;
-       len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(auth);
+       len = left - sizeof(auth);
 
        log_debug("%s: method %s length %zu",
            __func__, print_map(auth.auth_method, ikev2_auth_map), len);
@@ -1011,24 +940,6 @@ ikev2_pld_auth(struct iked *env, struct ikev2_payload *pld,
        return (0);
 }
 
-int
-ikev2_validate_nonce(struct iked_message *msg, size_t offset, size_t left,
-    struct ikev2_payload *pld)
-{
-       size_t           pld_length;
-
-       /* This will actually be caught by earlier checks. */
-       pld_length = betoh16(pld->pld_length);
-       if (pld_length < sizeof(*pld)) {
-               log_debug("%s: malformed payload: specified length smaller "
-                   "than minimum size (%zu < %zu)", __func__, pld_length,
-                   sizeof(*pld));
-               return (-1);
-       }
-
-       return (0);
-}
-
 int
 ikev2_pld_nonce(struct iked *env, struct ikev2_payload *pld,
     struct iked_message *msg, size_t offset, size_t left)
@@ -1037,22 +948,13 @@ ikev2_pld_nonce(struct iked *env, struct ikev2_payload *pld,
        uint8_t         *buf;
        uint8_t         *msgbuf = ibuf_data(msg->msg_data);
 
-       if (ikev2_validate_nonce(msg, offset, left, pld))
-               return (-1);
-
        buf = msgbuf + offset;
-       len = betoh16(pld->pld_length) - sizeof(*pld);
+       len = left;
 
        if (len == 0) {
                log_debug("%s: malformed payload: no NONCE given", __func__);
                return (-1);
        }
-       /* This will actually be caught by earlier checks. */
-       if (left < len) {
-               log_debug("%s: malformed payload: smaller than specified "
-                   "(%zu < %zu)", __func__, left, len);
-               return (-1);
-       }
 
        print_hex(buf, 0, len);
 
@@ -1070,20 +972,10 @@ ikev2_pld_nonce(struct iked *env, struct ikev2_payload *pld,
 
 int
 ikev2_validate_notify(struct iked_message *msg, size_t offset, size_t left,
-    struct ikev2_payload *pld, struct ikev2_notify *n)
+    struct ikev2_notify *n)
 {
        uint8_t         *msgbuf = ibuf_data(msg->msg_data);
-       size_t           pld_length;
 
-       pld_length = betoh16(pld->pld_length);
-       if (pld_length < sizeof(*pld) + sizeof(*n)) {
-               log_debug("%s: malformed payload: specified length smaller "
-                   "than minimum size (%zu < %zu)", __func__, pld_length,
-                   sizeof(*pld) + sizeof(*n));
-               return (-1);
-       }
-
-       /* This will actually be caught by earlier checks. */
        if (left < sizeof(*n)) {
                log_debug("%s: malformed payload: too short for header "
                    "(%zu < %zu)", __func__, left, sizeof(*n));
@@ -1110,7 +1002,7 @@ ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld,
        uint16_t                 signature_hash;
        uint8_t                  transform;
 
-       if (ikev2_validate_notify(msg, offset, left, pld, &n))
+       if (ikev2_validate_notify(msg, offset, left, &n))
                return (-1);
        type = betoh16(n.n_type);
 
@@ -1119,7 +1011,7 @@ ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld,
            print_map(n.n_protoid, ikev2_saproto_map), n.n_spisize,
            print_map(type, ikev2_n_map));
 
-       len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(n);
+       len = left - sizeof(n);
        if ((buf = ibuf_seek(msg->msg_data, offset + sizeof(n), len)) == NULL)
                return (-1);
 
@@ -1413,20 +1305,10 @@ ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld,
 
 int
 ikev2_validate_delete(struct iked_message *msg, size_t offset, size_t left,
-    struct ikev2_payload *pld, struct ikev2_delete *del)
+    struct ikev2_delete *del)
 {
        uint8_t         *msgbuf = ibuf_data(msg->msg_data);
-       size_t           pld_length;
 
-       pld_length = betoh16(pld->pld_length);
-       if (pld_length < sizeof(*pld) + sizeof(*del)) {
-               log_debug("%s: malformed payload: specified length smaller "
-                   "than minimum size (%zu < %zu)", __func__, pld_length,
-                   sizeof(*pld) + sizeof(*del));
-               return (-1);
-       }
-
-       /* This will actually be caught by earlier checks. */
        if (left < sizeof(*del)) {
                log_debug("%s: malformed payload: too short for header "
                    "(%zu < %zu)", __func__, left, sizeof(*del));
@@ -1457,7 +1339,7 @@ ikev2_pld_delete(struct iked *env, struct ikev2_payload *pld,
            msg->msg_parent->msg_response)
                return (0);
 
-       if (ikev2_validate_delete(msg, offset, left, pld, &del))
+       if (ikev2_validate_delete(msg, offset, left, &del))
                return (-1);
        cnt = betoh16(del.del_nspi);
        sz = del.del_spisize;
@@ -1467,7 +1349,7 @@ ikev2_pld_delete(struct iked *env, struct ikev2_payload *pld,
            sz, cnt);
 
        buf = msgbuf + offset + sizeof(del);
-       len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(del);
+       len = left - sizeof(del);
 
        print_hex(buf, 0, len);
 
@@ -1609,20 +1491,10 @@ ikev2_pld_delete(struct iked *env, struct ikev2_payload *pld,
 
 int
 ikev2_validate_ts(struct iked_message *msg, size_t offset, size_t left,
-    struct ikev2_payload *pld, struct ikev2_tsp *tsp)
+    struct ikev2_tsp *tsp)
 {
        uint8_t         *msgbuf = ibuf_data(msg->msg_data);
-       size_t           pld_length;
 
-       pld_length = betoh16(pld->pld_length);
-       if (pld_length < sizeof(*pld) + sizeof(*tsp)) {
-               log_debug("%s: malformed payload: specified length smaller "
-                   "than minimum size (%zu < %zu)", __func__, pld_length,
-                   sizeof(*pld) + sizeof(*tsp));
-               return (-1);
-       }
-
-       /* This will actually be caught by earlier checks. */
        if (left < sizeof(*tsp)) {
                log_debug("%s: malformed payload: too short for header "
                    "(%zu < %zu)", __func__, left, sizeof(*tsp));
@@ -1645,11 +1517,11 @@ ikev2_pld_ts(struct iked *env, struct ikev2_payload *pld,
        uint8_t                          buf[2][128];
        uint8_t                         *msgbuf = ibuf_data(msg->msg_data);
 
-       if (ikev2_validate_ts(msg, offset, left, pld, &tsp))
+       if (ikev2_validate_ts(msg, offset, left, &tsp))
                return (-1);
        offset += sizeof(tsp);
 
-       len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(tsp);
+       len = left - sizeof(tsp);
 
        log_debug("%s: count %d length %zu", __func__,
            tsp.tsp_count, len);
@@ -1707,7 +1579,7 @@ ikev2_pld_ts(struct iked *env, struct ikev2_payload *pld,
 
 int
 ikev2_pld_e(struct iked *env, struct ikev2_payload *pld,
-    struct iked_message *msg, size_t offset)
+    struct iked_message *msg, size_t offset, size_t left)
 {
        struct iked_sa          *sa = msg->msg_sa;
        struct ibuf             *e = NULL;
@@ -1718,7 +1590,7 @@ ikev2_pld_e(struct iked *env, struct ikev2_payload *pld,
        int                      ret = -1;
 
        buf = msgbuf + offset;
-       len = betoh16(pld->pld_length) - sizeof(*pld);
+       len = left;
 
        if ((e = ibuf_new(buf, len)) == NULL)
                goto done;
@@ -1755,20 +1627,10 @@ ikev2_pld_e(struct iked *env, struct ikev2_payload *pld,
 
 int
 ikev2_validate_cp(struct iked_message *msg, size_t offset, size_t left,
-    struct ikev2_payload *pld, struct ikev2_cp *cp)
+    struct ikev2_cp *cp)
 {
        uint8_t         *msgbuf = ibuf_data(msg->msg_data);
-       size_t           pld_length;
-
-       pld_length = betoh16(pld->pld_length);
-       if (pld_length < sizeof(*pld) + sizeof(*cp)) {
-               log_debug("%s: malformed payload: specified length smaller "
-                   "than minimum size (%zu < %zu)", __func__, pld_length,
-                   sizeof(*pld) + sizeof(*cp));
-               return (-1);
-       }
 
-       /* This will actually be caught by earlier checks. */
        if (left < sizeof(*cp)) {
                log_debug("%s: malformed payload: too short for header "
                    "(%zu < %zu)", __func__, left, sizeof(*cp));
@@ -1790,12 +1652,12 @@ ikev2_pld_cp(struct iked *env, struct ikev2_payload *pld,
        uint8_t                 *msgbuf = ibuf_data(msg->msg_data);
        struct iked_sa          *sa = msg->msg_sa;
 
-       if (ikev2_validate_cp(msg, offset, left, pld, &cp))
+       if (ikev2_validate_cp(msg, offset, left, &cp))
                return (-1);
        offset += sizeof(cp);
 
        buf = msgbuf + offset;
-       len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(cp);
+       len = left - sizeof(cp);
 
        log_debug("%s: type %s length %zu",
            __func__, print_map(cp.cp_type, ikev2_cp_map), len);
@@ -1823,20 +1685,10 @@ ikev2_pld_cp(struct iked *env, struct ikev2_payload *pld,
 
 int
 ikev2_validate_eap(struct iked_message *msg, size_t offset, size_t left,
-    struct ikev2_payload *pld, struct eap_header *hdr)
+    struct eap_header *hdr)
 {
        uint8_t         *msgbuf = ibuf_data(msg->msg_data);
-       size_t           pld_length;
-
-       pld_length = betoh16(pld->pld_length);
-       if (pld_length < sizeof(*pld) + sizeof(*hdr)) {
-               log_debug("%s: malformed payload: specified length smaller "
-                   "than minimum size (%zu < %zu)", __func__, pld_length,
-                   sizeof(*pld) + sizeof(*hdr));
-               return (-1);
-       }
 
-       /* This will actually be caught by earlier checks. */
        if (left < sizeof(*hdr)) {
                log_debug("%s: malformed payload: too short for header "
                    "(%zu < %zu)", __func__, left, sizeof(*hdr));
@@ -1856,7 +1708,7 @@ ikev2_pld_eap(struct iked *env, struct ikev2_payload *pld,
        struct iked_sa                  *sa = msg->msg_sa;
        size_t                           len;
 
-       if (ikev2_validate_eap(msg, offset, left, pld, &hdr))
+       if (ikev2_validate_eap(msg, offset, left, &hdr))
                return (-1);
        len = betoh16(hdr.eap_length);