From owner-svn-src-all@freebsd.org Mon Jun 4 18:51:07 2018 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 8AA27FE1865; Mon, 4 Jun 2018 18:51:07 +0000 (UTC) (envelope-from cem@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 417787F776; Mon, 4 Jun 2018 18:51:07 +0000 (UTC) (envelope-from cem@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 23C4D115F2; Mon, 4 Jun 2018 18:51:07 +0000 (UTC) (envelope-from cem@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id w54Ip77V095616; Mon, 4 Jun 2018 18:51:07 GMT (envelope-from cem@FreeBSD.org) Received: (from cem@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id w54Ip7Zn095615; Mon, 4 Jun 2018 18:51:07 GMT (envelope-from cem@FreeBSD.org) Message-Id: <201806041851.w54Ip7Zn095615@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: cem set sender to cem@FreeBSD.org using -f From: Conrad Meyer Date: Mon, 4 Jun 2018 18:51:07 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r334625 - head/sys/netipsec X-SVN-Group: head X-SVN-Commit-Author: cem X-SVN-Commit-Paths: head/sys/netipsec X-SVN-Commit-Revision: 334625 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.26 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 04 Jun 2018 18:51:07 -0000 Author: cem Date: Mon Jun 4 18:51:06 2018 New Revision: 334625 URL: https://svnweb.freebsd.org/changeset/base/334625 Log: Correctly handle the padding for IPv6-AH, as specified by RFC4302 The RFC specifies that under IPv6 the complete AH header must be 64 bit aligned, and under IPv4, 32 bit aligned. Prior to this change, we (along with other BSDs and MacOS) had violated this requirement. This makes it possible to set up IPv6-AH between Linux and BSD, and also probably between Windows and BSD. PR: 222684 Reported and tested by: Jason Mader Obtained from: NetBSD xform_ah.c 1.105 (b939fe2483972eb43d71bf990cfb7f26dece7839 NetBSD/src on GH) by Maxime Villard MFC after: 35.2731 hours Relnotes: probably (breaks ipv6 compat with older FreeBSD/NetBSD/MacOS) Sponsored by: Dell EMC Isilon Modified: head/sys/netipsec/xform_ah.c Modified: head/sys/netipsec/xform_ah.c ============================================================================== --- head/sys/netipsec/xform_ah.c Mon Jun 4 18:47:14 2018 (r334624) +++ head/sys/netipsec/xform_ah.c Mon Jun 4 18:51:06 2018 (r334625) @@ -147,11 +147,21 @@ ah_hdrsiz(struct secasvar *sav) size_t size; if (sav != NULL) { - int authsize; + int authsize, rplen, align; + IPSEC_ASSERT(sav->tdb_authalgxform != NULL, ("null xform")); /*XXX not right for null algorithm--does it matter??*/ + + /* RFC4302: use the correct alignment. */ + align = sizeof(uint32_t); +#ifdef INET6 + if (sav->sah->saidx.dst.sa.sa_family == AF_INET6) { + align = sizeof(uint64_t); + } +#endif + rplen = HDRSIZE(sav); authsize = AUTHSIZE(sav); - size = roundup(authsize, sizeof (u_int32_t)) + HDRSIZE(sav); + size = roundup(rplen + authsize, align); } else { /* default guess */ size = sizeof (struct ah) + sizeof (u_int32_t) + 16; @@ -535,7 +545,7 @@ ah_input(struct mbuf *m, struct secasvar *sav, int ski struct xform_data *xd; struct newah *ah; uint64_t cryptoid; - int hl, rplen, authsize, error; + int hl, rplen, authsize, ahsize, error; IPSEC_ASSERT(sav != NULL, ("null SA")); IPSEC_ASSERT(sav->key_auth != NULL, ("null authentication key")); @@ -569,23 +579,24 @@ ah_input(struct mbuf *m, struct secasvar *sav, int ski SECASVAR_UNLOCK(sav); /* Verify AH header length. */ - hl = ah->ah_len * sizeof (u_int32_t); + hl = sizeof(struct ah) + (ah->ah_len * sizeof (u_int32_t)); ahx = sav->tdb_authalgxform; authsize = AUTHSIZE(sav); - if (hl != authsize + rplen - sizeof (struct ah)) { + ahsize = ah_hdrsiz(sav); + if (hl != ahsize) { DPRINTF(("%s: bad authenticator length %u (expecting %lu)" " for packet in SA %s/%08lx\n", __func__, hl, - (u_long) (authsize + rplen - sizeof (struct ah)), + (u_long)ahsize, ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)), (u_long) ntohl(sav->spi))); AHSTAT_INC(ahs_badauthl); error = EACCES; goto bad; } - if (skip + authsize + rplen > m->m_pkthdr.len) { + if (skip + ahsize > m->m_pkthdr.len) { DPRINTF(("%s: bad mbuf length %u (expecting %lu)" " for packet in SA %s/%08lx\n", __func__, - m->m_pkthdr.len, (u_long) (skip + authsize + rplen), + m->m_pkthdr.len, (u_long)(skip + ahsize), ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)), (u_long) ntohl(sav->spi))); AHSTAT_INC(ahs_badauthl); @@ -689,7 +700,7 @@ ah_input_cb(struct cryptop *crp) struct secasindex *saidx; caddr_t ptr; uint64_t cryptoid; - int authsize, rplen, error, skip, protoff; + int authsize, rplen, ahsize, error, skip, protoff; uint8_t nxt; m = (struct mbuf *) crp->crp_buf; @@ -736,6 +747,7 @@ ah_input_cb(struct cryptop *crp) /* Figure out header size. */ rplen = HDRSIZE(sav); authsize = AUTHSIZE(sav); + ahsize = ah_hdrsiz(sav); /* Copy authenticator off the packet. */ m_copydata(m, skip + rplen, authsize, calc); @@ -784,7 +796,7 @@ ah_input_cb(struct cryptop *crp) /* * Remove the AH header and authenticator from the mbuf. */ - error = m_striphdr(m, skip, rplen + authsize); + error = m_striphdr(m, skip, ahsize); if (error) { DPRINTF(("%s: mangled mbuf chain for SA %s/%08lx\n", __func__, ipsec_address(&saidx->dst, buf, sizeof(buf)), @@ -839,7 +851,7 @@ ah_output(struct mbuf *m, struct secpolicy *sp, struct struct newah *ah; uint64_t cryptoid; uint16_t iplen; - int error, rplen, authsize, maxpacketsize, roff; + int error, rplen, authsize, ahsize, maxpacketsize, roff; uint8_t prot; IPSEC_ASSERT(sav != NULL, ("null SA")); @@ -850,6 +862,8 @@ ah_output(struct mbuf *m, struct secpolicy *sp, struct /* Figure out header size. */ rplen = HDRSIZE(sav); + authsize = AUTHSIZE(sav); + ahsize = ah_hdrsiz(sav); /* Check for maximum packet size violations. */ switch (sav->sah->saidx.dst.sa.sa_family) { @@ -873,13 +887,12 @@ ah_output(struct mbuf *m, struct secpolicy *sp, struct error = EPFNOSUPPORT; goto bad; } - authsize = AUTHSIZE(sav); - if (rplen + authsize + m->m_pkthdr.len > maxpacketsize) { + if (ahsize + m->m_pkthdr.len > maxpacketsize) { DPRINTF(("%s: packet in SA %s/%08lx got too big " "(len %u, max len %u)\n", __func__, ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)), (u_long) ntohl(sav->spi), - rplen + authsize + m->m_pkthdr.len, maxpacketsize)); + ahsize + m->m_pkthdr.len, maxpacketsize)); AHSTAT_INC(ahs_toobig); error = EMSGSIZE; goto bad; @@ -899,11 +912,10 @@ ah_output(struct mbuf *m, struct secpolicy *sp, struct } /* Inject AH header. */ - mi = m_makespace(m, skip, rplen + authsize, &roff); + mi = m_makespace(m, skip, ahsize, &roff); if (mi == NULL) { DPRINTF(("%s: failed to inject %u byte AH header for SA " - "%s/%08lx\n", __func__, - rplen + authsize, + "%s/%08lx\n", __func__, ahsize, ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)), (u_long) ntohl(sav->spi))); AHSTAT_INC(ahs_hdrops); /*XXX differs from openbsd */ @@ -919,13 +931,17 @@ ah_output(struct mbuf *m, struct secpolicy *sp, struct /* Initialize the AH header. */ m_copydata(m, protoff, sizeof(u_int8_t), (caddr_t) &ah->ah_nxt); - ah->ah_len = (rplen + authsize - sizeof(struct ah)) / sizeof(u_int32_t); + ah->ah_len = (ahsize - sizeof(struct ah)) / sizeof(u_int32_t); ah->ah_reserve = 0; ah->ah_spi = sav->spi; /* Zeroize authenticator. */ m_copyback(m, skip + rplen, authsize, ipseczeroes); + /* Zeroize padding */ + m_copyback(m, skip + rplen + authsize, ahsize - (rplen + authsize), + ipseczeroes); + /* Insert packet replay counter, as requested. */ SECASVAR_LOCK(sav); if (sav->replay) { @@ -994,7 +1010,7 @@ ah_output(struct mbuf *m, struct secpolicy *sp, struct bcopy(((caddr_t)(xd + 1)) + offsetof(struct ip, ip_len), (caddr_t) &iplen, sizeof(u_int16_t)); - iplen = htons(ntohs(iplen) + rplen + authsize); + iplen = htons(ntohs(iplen) + ahsize); m_copyback(m, offsetof(struct ip, ip_len), sizeof(u_int16_t), (caddr_t) &iplen); break; @@ -1005,7 +1021,7 @@ ah_output(struct mbuf *m, struct secpolicy *sp, struct bcopy(((caddr_t)(xd + 1)) + offsetof(struct ip6_hdr, ip6_plen), (caddr_t) &iplen, sizeof(uint16_t)); - iplen = htons(ntohs(iplen) + rplen + authsize); + iplen = htons(ntohs(iplen) + ahsize); m_copyback(m, offsetof(struct ip6_hdr, ip6_plen), sizeof(uint16_t), (caddr_t) &iplen); break;