Index: head/sys/netipsec/keydb.h =================================================================== --- head/sys/netipsec/keydb.h +++ head/sys/netipsec/keydb.h @@ -197,6 +197,8 @@ #define SAV_ISCTR(_sav) ((_sav)->alg_enc == SADB_X_EALG_AESCTR) #define SAV_ISCTRORGCM(_sav) (SAV_ISCTR((_sav)) || SAV_ISGCM((_sav))) +#define IPSEC_SEQH_SHIFT 32 + /* Replay prevention, protected by SECASVAR_LOCK: * (m) locked by mtx * (c) read only except during creation / free Index: head/sys/netipsec/xform_ah.c =================================================================== --- head/sys/netipsec/xform_ah.c +++ head/sys/netipsec/xform_ah.c @@ -236,6 +236,10 @@ memset(&csp, 0, sizeof(csp)); csp.csp_mode = CSP_MODE_DIGEST; + + if (sav->flags & SADB_X_SAFLAGS_ESN) + csp.csp_flags |= CSP_F_ESN; + error = ah_init0(sav, xsp, &csp); return error ? error : crypto_newsession(&sav->tdb_cryptoid, &csp, V_crypto_support); @@ -654,6 +658,12 @@ crp->crp_callback = ah_input_cb; crp->crp_opaque = xd; + if (sav->flags & SADB_X_SAFLAGS_ESN && + sav->replay != NULL && sav->replay->wsize != 0) { + seqh = htonl(seqh); + memcpy(crp->crp_esn, &seqh, sizeof(seqh)); + } + /* These are passed as-is to the callback. */ xd->sav = sav; xd->nxt = hl; @@ -834,6 +844,7 @@ uint16_t iplen; int error, rplen, authsize, ahsize, maxpacketsize, roff; uint8_t prot; + uint32_t seqh; IPSEC_ASSERT(sav != NULL, ("null SA")); ahx = sav->tdb_authalgxform; @@ -1030,6 +1041,11 @@ crypto_use_mbuf(crp, m); crp->crp_callback = ah_output_cb; crp->crp_opaque = xd; + + if (sav->flags & SADB_X_SAFLAGS_ESN && sav->replay != NULL) { + seqh = htonl((uint32_t)(sav->replay->count >> IPSEC_SEQH_SHIFT)); + memcpy(crp->crp_esn, &seqh, sizeof(seqh)); + } /* These are passed as-is to the callback. */ xd->sp = sp; Index: head/sys/netipsec/xform_esp.c =================================================================== --- head/sys/netipsec/xform_esp.c +++ head/sys/netipsec/xform_esp.c @@ -80,6 +80,8 @@ #include #include +#define SPI_SIZE 4 + VNET_DEFINE(int, esp_enable) = 1; VNET_DEFINE_STATIC(int, esp_ctr_compatibility) = 1; #define V_esp_ctr_compatibility VNET(esp_ctr_compatibility) @@ -219,9 +221,13 @@ return EINVAL; } csp.csp_mode = CSP_MODE_AEAD; - } else if (sav->alg_auth != 0) + if (sav->flags & SADB_X_SAFLAGS_ESN) + csp.csp_flags |= CSP_F_SEPARATE_AAD; + } else if (sav->alg_auth != 0) { csp.csp_mode = CSP_MODE_ETA; - else + if (sav->flags & SADB_X_SAFLAGS_ESN) + csp.csp_flags |= CSP_F_ESN; + } else csp.csp_mode = CSP_MODE_CIPHER; /* Initialize crypto session. */ @@ -263,6 +269,7 @@ crypto_session_t cryptoid; int alen, error, hlen, plen; uint32_t seqh; + const struct crypto_session_params *csp; IPSEC_ASSERT(sav != NULL, ("null SA")); IPSEC_ASSERT(sav->tdb_encalgxform != NULL, ("null encoding xform")); @@ -329,6 +336,7 @@ error = EACCES; goto bad; } + seqh = htonl(seqh); } cryptoid = sav->tdb_cryptoid; SECASVAR_UNLOCK(sav); @@ -350,19 +358,49 @@ xd = malloc(sizeof(*xd), M_XDATA, M_NOWAIT | M_ZERO); if (xd == NULL) { DPRINTF(("%s: failed to allocate xform_data\n", __func__)); - ESPSTAT_INC(esps_crypto); - crypto_freereq(crp); - error = ENOBUFS; - goto bad; + goto xd_fail; } if (esph != NULL) { crp->crp_op = CRYPTO_OP_VERIFY_DIGEST; - crp->crp_aad_start = skip; if (SAV_ISGCM(sav)) crp->crp_aad_length = 8; /* RFC4106 5, SPI + SN */ else crp->crp_aad_length = hlen; + + csp = crypto_get_params(crp->crp_session); + if ((csp->csp_flags & CSP_F_SEPARATE_AAD) && + (sav->replay != NULL) && (sav->replay->wsize != 0)) { + int aad_skip; + + crp->crp_aad_length += sizeof(seqh); + crp->crp_aad = malloc(crp->crp_aad_length, M_XDATA, M_NOWAIT); + if (crp->crp_aad == NULL) { + DPRINTF(("%s: failed to allocate xform_data\n", + __func__)); + goto crp_aad_fail; + } + + /* SPI */ + m_copydata(m, skip, SPI_SIZE, crp->crp_aad); + aad_skip = SPI_SIZE; + + /* ESN */ + bcopy(&seqh, (char *)crp->crp_aad + aad_skip, sizeof(seqh)); + aad_skip += sizeof(seqh); + + /* Rest of aad */ + if (crp->crp_aad_length - aad_skip > 0) + m_copydata(m, skip + SPI_SIZE, + crp->crp_aad_length - aad_skip, + (char *)crp->crp_aad + aad_skip); + } else + crp->crp_aad_start = skip; + + if (csp->csp_flags & CSP_F_ESN && + sav->replay != NULL && sav->replay->wsize != 0) + memcpy(crp->crp_esn, &seqh, sizeof(seqh)); + crp->crp_digest_start = m->m_pkthdr.len - alen; } @@ -423,6 +461,13 @@ crp->crp_iv_start = skip + hlen - sav->ivlen; return (crypto_dispatch(crp)); + +crp_aad_fail: + free(xd, M_XDATA); +xd_fail: + crypto_freereq(crp); + ESPSTAT_INC(esps_crypto); + error = ENOBUFS; bad: m_freem(m); key_freesav(&sav); @@ -505,6 +550,7 @@ /* Release the crypto descriptors */ free(xd, M_XDATA), xd = NULL; + free(crp->crp_aad, M_XDATA), crp->crp_aad = NULL; crypto_freereq(crp), crp = NULL; /* @@ -614,8 +660,10 @@ m_freem(m); if (xd != NULL) free(xd, M_XDATA); - if (crp != NULL) + if (crp != NULL) { + free(crp->crp_aad, M_XDATA); crypto_freereq(crp); + } return error; } /* @@ -639,6 +687,8 @@ int hlen, rlen, padding, blks, alen, i, roff; int error, maxpacketsize; uint8_t prot; + uint32_t seqh; + const struct crypto_session_params *csp; IPSEC_ASSERT(sav != NULL, ("null SA")); esph = sav->tdb_authalgxform; @@ -745,6 +795,8 @@ bcopy((caddr_t) &replay, mtod(mo, caddr_t) + roff + sizeof(uint32_t), sizeof(uint32_t)); + + seqh = htonl((uint32_t)(sav->replay->count >> IPSEC_SEQH_SHIFT)); } cryptoid = sav->tdb_cryptoid; if (SAV_ISCTRORGCM(sav)) @@ -801,13 +853,10 @@ } /* IPsec-specific opaque crypto info. */ - xd = malloc(sizeof(struct xform_data), M_XDATA, M_NOWAIT | M_ZERO); + xd = malloc(sizeof(struct xform_data), M_XDATA, M_NOWAIT | M_ZERO); if (xd == NULL) { - crypto_freereq(crp); DPRINTF(("%s: failed to allocate xform_data\n", __func__)); - ESPSTAT_INC(esps_crypto); - error = ENOBUFS; - goto bad; + goto xd_fail; } /* Encryption descriptor. */ @@ -855,15 +904,54 @@ if (esph) { /* Authentication descriptor. */ crp->crp_op |= CRYPTO_OP_COMPUTE_DIGEST; - crp->crp_aad_start = skip; if (SAV_ISGCM(sav)) crp->crp_aad_length = 8; /* RFC4106 5, SPI + SN */ else crp->crp_aad_length = hlen; + + csp = crypto_get_params(crp->crp_session); + if (csp->csp_flags & CSP_F_SEPARATE_AAD && + sav->replay != NULL) { + int aad_skip; + + crp->crp_aad_length += sizeof(seqh); + crp->crp_aad = malloc(crp->crp_aad_length, M_XDATA, M_NOWAIT); + if (crp->crp_aad == NULL) { + DPRINTF(("%s: failed to allocate xform_data\n", + __func__)); + goto crp_aad_fail; + } + + /* SPI */ + m_copydata(m, skip, SPI_SIZE, crp->crp_aad); + aad_skip = SPI_SIZE; + + /* ESN */ + bcopy(&seqh, (char *)crp->crp_aad + aad_skip, sizeof(seqh)); + aad_skip += sizeof(seqh); + + /* Rest of aad */ + if (crp->crp_aad_length - aad_skip > 0) + m_copydata(m, skip + SPI_SIZE, + crp->crp_aad_length - aad_skip, + (char *)crp->crp_aad + aad_skip); + } else + crp->crp_aad_start = skip; + + if (csp->csp_flags & CSP_F_ESN && sav->replay != NULL) + memcpy(crp->crp_esn, &seqh, sizeof(seqh)); + crp->crp_digest_start = m->m_pkthdr.len - alen; } return crypto_dispatch(crp); + +crp_aad_fail: + free(xd, M_XDATA); +xd_fail: + crypto_freereq(crp); + ESPSTAT_INC(esps_crypto); + error = ENOBUFS; bad: if (m) m_freem(m); @@ -918,6 +1006,7 @@ goto bad; } free(xd, M_XDATA); + free(crp->crp_aad, M_XDATA); crypto_freereq(crp); ESPSTAT_INC(esps_hist[sav->alg_enc]); if (sav->tdb_authalgxform != NULL) @@ -951,6 +1040,7 @@ bad: CURVNET_RESTORE(); free(xd, M_XDATA); + free(crp->crp_aad, M_XDATA); crypto_freereq(crp); key_freesav(&sav); key_freesp(&sp);