Index: lib/libipsec/pfkey.c =================================================================== --- lib/libipsec/pfkey.c +++ lib/libipsec/pfkey.c @@ -1825,6 +1825,7 @@ case SADB_X_EXT_SA_REPLAY: case SADB_X_EXT_NEW_ADDRESS_SRC: case SADB_X_EXT_NEW_ADDRESS_DST: + case SADB_X_EXT_SA_TFC_LENGTH: mhp[ext->sadb_ext_type] = (caddr_t)ext; break; default: Index: lib/libipsec/pfkey_dump.c =================================================================== --- lib/libipsec/pfkey_dump.c +++ lib/libipsec/pfkey_dump.c @@ -230,6 +230,7 @@ struct sadb_ident *m_sid, *m_did; struct sadb_sens *m_sens; struct sadb_x_sa_replay *m_sa_replay; + struct sadb_x_sa_tfc_length *m_sa_tfc_length; struct sadb_x_nat_t_type *natt_type; struct sadb_x_nat_t_port *natt_sport, *natt_dport; struct sadb_address *natt_oai, *natt_oar; @@ -258,6 +259,7 @@ m_did = (struct sadb_ident *)mhp[SADB_EXT_IDENTITY_DST]; m_sens = (struct sadb_sens *)mhp[SADB_EXT_SENSITIVITY]; m_sa_replay = (struct sadb_x_sa_replay *)mhp[SADB_X_EXT_SA_REPLAY]; + m_sa_tfc_length = (struct sadb_x_sa_tfc_length *)mhp[SADB_X_EXT_SA_TFC_LENGTH]; natt_type = (struct sadb_x_nat_t_type *)mhp[SADB_X_EXT_NAT_T_TYPE]; natt_sport = (struct sadb_x_nat_t_port *)mhp[SADB_X_EXT_NAT_T_SPORT]; natt_dport = (struct sadb_x_nat_t_port *)mhp[SADB_X_EXT_NAT_T_DPORT]; @@ -350,6 +352,10 @@ m_sa->sadb_sa_replay, m_sa->sadb_sa_flags); + /* tfc padding length */ + printf("tfcpadding=%d ", m_sa_tfc_length ? + m_sa_tfc_length->sadb_x_sa_tfc_length_length : 0); + /* state */ printf("state="); GETMSGSTR(str_state, m_sa->sadb_sa_state); Index: sys/net/pfkeyv2.h =================================================================== --- sys/net/pfkeyv2.h +++ sys/net/pfkeyv2.h @@ -297,6 +297,14 @@ }; _Static_assert(sizeof(struct sadb_x_sa_replay) == 8, "struct size mismatch"); +/* TFC padding length */ +struct sadb_x_sa_tfc_length { + u_int16_t sadb_x_sa_tfc_length_len; + u_int16_t sadb_x_sa_tfc_length_exttype; + int32_t sadb_x_sa_tfc_length_length; +}; +_Static_assert(sizeof(struct sadb_x_sa_tfc_length) == 8, "struct size mismatch"); + #define SADB_EXT_RESERVED 0 #define SADB_EXT_SA 1 #define SADB_EXT_LIFETIME_CURRENT 2 @@ -327,7 +335,8 @@ #define SADB_X_EXT_SA_REPLAY 26 /* Replay window override. */ #define SADB_X_EXT_NEW_ADDRESS_SRC 27 #define SADB_X_EXT_NEW_ADDRESS_DST 28 -#define SADB_EXT_MAX 28 +#define SADB_X_EXT_SA_TFC_LENGTH 29 +#define SADB_EXT_MAX 29 #define SADB_SATYPE_UNSPEC 0 #define SADB_SATYPE_AH 2 Index: sys/netipsec/key.c =================================================================== --- sys/netipsec/key.c +++ sys/netipsec/key.c @@ -385,6 +385,7 @@ sizeof(struct sadb_x_sa_replay), /* SADB_X_EXT_SA_REPLAY */ sizeof(struct sadb_address), /* SADB_X_EXT_NEW_ADDRESS_SRC */ sizeof(struct sadb_address), /* SADB_X_EXT_NEW_ADDRESS_DST */ + sizeof(struct sadb_x_sa_tfc_length),/* SADB_X_EXT_SA_TFC_LENGTH */ }; _Static_assert(sizeof(minsize)/sizeof(int) == SADB_EXT_MAX + 1, "minsize size mismatch"); @@ -418,6 +419,7 @@ sizeof(struct sadb_x_sa_replay), /* SADB_X_EXT_SA_REPLAY */ 0, /* SADB_X_EXT_NEW_ADDRESS_SRC */ 0, /* SADB_X_EXT_NEW_ADDRESS_DST */ + sizeof(struct sadb_x_sa_tfc_length),/* SADB_X_EXT_SA_TFC_LENGTH */ }; _Static_assert(sizeof(maxsize)/sizeof(int) == SADB_EXT_MAX + 1, "minsize size mismatch"); @@ -673,6 +675,7 @@ static struct mbuf *key_setsadbxtype(u_int16_t); static struct mbuf *key_setsadbxsa2(u_int8_t, u_int32_t, u_int32_t); static struct mbuf *key_setsadbxsareplay(u_int32_t); +static struct mbuf *key_setsadbxsatfclength(int32_t); static struct mbuf *key_setsadbxpolicy(u_int16_t, u_int8_t, u_int32_t, u_int32_t); static struct seckey *key_dup_keymsg(const struct sadb_key *, size_t, @@ -2959,6 +2962,7 @@ sav->seq = mhp->msg->sadb_msg_seq; sav->state = SADB_SASTATE_LARVAL; sav->pid = (pid_t)mhp->msg->sadb_msg_pid; + sav->tfc = 0; SAV_INITREF(sav); again: sah = key_getsah(saidx); @@ -3384,6 +3388,41 @@ } } + /* TFC padding */ + sav->tfc = 0; + if (!SADB_CHECKHDR(mhp, SADB_X_EXT_SA_TFC_LENGTH)) { + int maxpacketsize; + if (SADB_CHECKLEN(mhp, SADB_X_EXT_SA_TFC_LENGTH)) { + error = EINVAL; + goto fail; + } + error = 0; + sav->tfc = ((const struct sadb_x_sa_tfc_length*) + mhp->ext[SADB_X_EXT_SA_TFC_LENGTH])->sadb_x_sa_tfc_length_length; + switch (sav->sah->saidx.dst.sa.sa_family) + { +#ifdef INET + case AF_INET: + maxpacketsize = IP_MAXPACKET; + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + maxpacketsize = IPV6_MAXPACKET; + break; +#endif /* INET6 */ + default: + DPRINTF(("%s: unknown/unsupported protocol " + "family %d, SA %s/%08lx\n", __func__, + saidx->dst.sa.sa_family, ipsec_address(&saidx->dst, + buf, sizeof(buf)), (u_long) ntohl(sav->spi))); + error = EPFNOSUPPORT; + goto fail; + } + if (sav->tfc > maxpacketsize) + sav->tfc = maxpacketsize; + } + /* Authentication keys */ if (!SADB_CHECKHDR(mhp, SADB_EXT_KEY_AUTH)) { if (SADB_CHECKLEN(mhp, SADB_EXT_KEY_AUTH)) { @@ -3534,6 +3573,14 @@ if (error != 0) goto fail; + if (sav->tfc > 0 && sav->natt) + { + if (sav->tfc > sizeof(struct ip) + sizeof(struct udphdr)) + sav->tfc -= sizeof(struct ip) + sizeof(struct udphdr); + else + sav->tfc = 0; + } + /* Initialize lifetime for CURRENT */ sav->firstused = 0; sav->created = time_second; @@ -3567,7 +3614,7 @@ SADB_X_EXT_NAT_T_TYPE, SADB_X_EXT_NAT_T_SPORT, SADB_X_EXT_NAT_T_DPORT, SADB_X_EXT_NAT_T_OAI, SADB_X_EXT_NAT_T_OAR, - SADB_X_EXT_NAT_T_FRAG, + SADB_X_EXT_NAT_T_FRAG, SADB_X_EXT_SA_TFC_LENGTH, }; uint32_t replay_count; @@ -3605,6 +3652,15 @@ goto fail; break; + case SADB_X_EXT_SA_TFC_LENGTH: + if (sav->tfc <= 0) + continue; + + m = key_setsadbxsatfclength(sav->tfc); + if (!m) + goto fail; + break; + case SADB_EXT_ADDRESS_SRC: m = key_setsadbaddr(SADB_EXT_ADDRESS_SRC, &sav->sah->saidx.src.sa, @@ -3928,6 +3984,32 @@ return m; } +/* + * Set data into sadb_x_sa_tfc_length + */ +static struct mbuf * +key_setsadbxsatfclength(int32_t tfc_length) +{ + struct mbuf *m; + struct sadb_x_sa_tfc_length *p; + size_t len; + + len = PFKEY_ALIGN8(sizeof(struct sadb_x_sa_tfc_length)); + m = m_get2(len, M_NOWAIT, MT_DATA, 0); + if (m == NULL) + return (NULL); + m_align(m, len); + m->m_len = len; + p = mtod(m, struct sadb_x_sa_tfc_length *); + + bzero(p, len); + p->sadb_x_sa_tfc_length_len = PFKEY_UNIT64(len); + p->sadb_x_sa_tfc_length_exttype = SADB_X_EXT_SA_TFC_LENGTH; + p->sadb_x_sa_tfc_length_length = tfc_length; + + return m; +} + /* * Set a type in sadb_x_nat_t_type. */ @@ -7333,6 +7415,16 @@ m_cat(result, m); } + if (sav->tfc > 0) + { + m = key_setsadbxsatfclength(sav->tfc); + if (!m) { + error = ENOBUFS; + goto fail; + } + m_cat(result, m); + } + /* create lifetime extension (current and soft) */ len = PFKEY_ALIGN8(sizeof(*lt)) * 2; m = m_get2(len, M_NOWAIT, MT_DATA, 0); @@ -8079,6 +8171,7 @@ case SADB_X_EXT_SA_REPLAY: case SADB_X_EXT_NEW_ADDRESS_SRC: case SADB_X_EXT_NEW_ADDRESS_DST: + case SADB_X_EXT_SA_TFC_LENGTH: /* duplicate check */ /* * XXX Are there duplication payloads of either Index: sys/netipsec/key_debug.c =================================================================== --- sys/netipsec/key_debug.c +++ sys/netipsec/key_debug.c @@ -78,6 +78,7 @@ static void kdebug_sadb_x_sa2(struct sadb_ext *); static void kdebug_sadb_x_sa_replay(struct sadb_ext *); static void kdebug_sadb_x_natt(struct sadb_ext *); +static void kdebug_sadb_x_sa_tfc_length(struct sadb_ext *); #ifndef _KERNEL #define panic(fmt, ...) { printf(fmt, ## __VA_ARGS__); exit(-1); } @@ -253,6 +254,9 @@ case SADB_X_EXT_NAT_T_DPORT: kdebug_sadb_x_natt(ext); break; + case SADB_X_EXT_SA_TFC_LENGTH: + kdebug_sadb_x_sa_tfc_length(ext); + break; default: printf("%s: invalid ext_type %u\n", __func__, ext->sadb_ext_type); @@ -519,6 +523,20 @@ } } +static void +kdebug_sadb_x_sa_tfc_length(struct sadb_ext *ext) +{ + struct sadb_x_sa_tfc_length *tfc_length; + + /* sanity check */ + if (ext == NULL) + panic("%s: NULL pointer was passed.\n", __func__); + + tfc_length = (struct sadb_x_sa_tfc_length *)ext; + printf("sadb_x_sa_tfc_length{ length=%d }\n", + tfc_length->sadb_x_sa_tfc_length_length); +} + void kdebug_sadb_x_policy(struct sadb_ext *ext) { Index: sys/netipsec/keydb.h =================================================================== --- sys/netipsec/keydb.h +++ sys/netipsec/keydb.h @@ -185,6 +185,8 @@ uint64_t cntr; /* counter for GCM and CTR */ volatile u_int refcnt; /* reference count */ + + int32_t tfc; /* TFC padding length (ESPv3) */ }; #define SECASVAR_LOCK(_sav) mtx_lock((_sav)->lock) Index: sys/netipsec/xform_esp.c =================================================================== --- sys/netipsec/xform_esp.c +++ sys/netipsec/xform_esp.c @@ -59,6 +59,7 @@ #include #include #include +#include #include #include @@ -669,8 +670,9 @@ uint64_t cntr; crypto_session_t cryptoid; int hlen, rlen, padding, blks, alen, i, roff; - int error, maxpacketsize; + int error, maxpacketsize, tfclen; uint8_t prot; + int pktlen; IPSEC_ASSERT(sav != NULL, ("null SA")); esph = sav->tdb_authalgxform; @@ -688,9 +690,6 @@ */ blks = MAX(4, espx->blocksize); /* Cipher blocksize */ - /* XXX clamp padding length a la KAME??? */ - padding = ((blks - ((rlen + 2) % blks)) % blks) + 2; - alen = xform_ah_authsize(esph); ESPSTAT_INC(esps_output); @@ -717,15 +716,34 @@ error = EPFNOSUPPORT; goto bad; } + + pktlen = skip + hlen + rlen + alen; + if (sav->tfc > 0 && sav->tfc > pktlen) + { + tfclen = sav->tfc - pktlen; + /* XXX clamp padding length a la KAME??? */ + padding = ((blks - ((rlen + tfclen + 2) % blks)) % blks) + 2; + pktlen += padding + tfclen; + if (pktlen > maxpacketsize && tfclen > blks) + tfclen -= blks; + } + else + { + tfclen = 0; + /* XXX clamp padding length a la KAME??? */ + padding = ((blks - ((rlen + 2) % blks)) % blks) + 2; + pktlen += padding; + } + /* DPRINTF(("%s: skip %d hlen %d rlen %d padding %d alen %d blksd %d\n", __func__, skip, hlen, rlen, padding, alen, blks)); */ - if (skip + hlen + rlen + padding + alen > maxpacketsize) { + if (pktlen > maxpacketsize) { DPRINTF(("%s: packet in SA %s/%08lx got too big " "(len %u, max len %u)\n", __func__, ipsec_address(&saidx->dst, buf, sizeof(buf)), (u_long) ntohl(sav->spi), - skip + hlen + rlen + padding + alen, maxpacketsize)); + pktlen, maxpacketsize)); ESPSTAT_INC(esps_toobig); error = EMSGSIZE; goto bad; @@ -781,7 +799,7 @@ * Add padding -- better to do it ourselves than use the crypto engine, * although if/when we support compression, we'd have to do that. */ - pad = (u_char *) m_pad(m, padding + alen); + pad = (u_char *) m_pad(m, tfclen + padding + alen); if (pad == NULL) { DPRINTF(("%s: m_pad failed for SA %s/%08lx\n", __func__, ipsec_address(&saidx->dst, buf, sizeof(buf)), @@ -797,20 +815,22 @@ */ switch (sav->flags & SADB_X_EXT_PMASK) { case SADB_X_EXT_PRAND: - arc4random_buf(pad, padding - 2); + arc4random_buf(pad, tfclen + padding - 2); break; case SADB_X_EXT_PZERO: - bzero(pad, padding - 2); + bzero(pad, tfclen + padding - 2); break; case SADB_X_EXT_PSEQ: - for (i = 0; i < padding - 2; i++) - pad[i] = i+1; + for (i = 0; i < tfclen; i++) + pad[i] = i + 1; + for (i = tfclen; i < tfclen + padding - 2; i++) + pad[i] = i - tfclen + 1; break; } /* Fix padding length and Next Protocol in padding itself. */ - pad[padding - 2] = padding - 2; - m_copydata(m, protoff, sizeof(u_int8_t), pad + padding - 1); + pad[tfclen + padding - 2] = padding - 2; + m_copydata(m, protoff, sizeof(u_int8_t), pad + tfclen + padding - 1); /* Fix Next Protocol in IPv4/IPv6 header. */ prot = IPPROTO_ESP;