Index: sys/netipsec/xform_ah.c =================================================================== --- sys/netipsec/xform_ah.c +++ 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, 4); + } + /* 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; @@ -1031,6 +1042,11 @@ 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 >> 32)); + memcpy(crp->crp_esn, &seqh, 4); + } + /* These are passed as-is to the callback. */ xd->sp = sp; xd->sav = sav; Index: sys/netipsec/xform_esp.c =================================================================== --- sys/netipsec/xform_esp.c +++ sys/netipsec/xform_esp.c @@ -219,8 +219,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; + if (sav->flags & SADB_X_SAFLAGS_ESN) + csp.csp_flags |= CSP_F_ESN; + } else csp.csp_mode = CSP_MODE_CIPHER; @@ -263,6 +268,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 +335,7 @@ error = EACCES; goto bad; } + seqh = htonl(seqh); } cryptoid = sav->tdb_cryptoid; SECASVAR_UNLOCK(sav); @@ -350,24 +357,48 @@ 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; } + crp->crp_flags = CRYPTO_F_CBIFSYNC; 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) { + crp->crp_aad_length += 4; + 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, 4, crp->crp_aad); + + /* ESN */ + bcopy(&seqh, (char *)crp->crp_aad + 4, 4); + + /* Rest of aad */ + if (crp->crp_aad_length - 8 > 0) + m_copydata(m, skip + 4, crp->crp_aad_length - 4, + (char *)crp->crp_aad + 8); + } 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, 4); + crp->crp_digest_start = m->m_pkthdr.len - alen; } /* Crypto operation descriptor */ - crp->crp_flags = CRYPTO_F_CBIFSYNC; if (V_async_crypto) crp->crp_flags |= CRYPTO_F_ASYNC | CRYPTO_F_ASYNC_KEEPORDER; crypto_use_mbuf(crp, m); @@ -423,6 +454,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 +543,10 @@ /* Release the crypto descriptors */ free(xd, M_XDATA), xd = NULL; + if (crp->crp_aad) { + free(crp->crp_aad, M_XDATA); + crp->crp_aad = NULL; + } crypto_freereq(crp), crp = NULL; /* @@ -614,6 +656,8 @@ m_freem(m); if (xd != NULL) free(xd, M_XDATA); + if (crp && crp->crp_aad) + free(crp->crp_aad, M_XDATA); if (crp != NULL) crypto_freereq(crp); return error; @@ -639,6 +683,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 +791,8 @@ bcopy((caddr_t) &replay, mtod(mo, caddr_t) + roff + sizeof(uint32_t), sizeof(uint32_t)); + + seqh = htonl((uint32_t)(sav->replay->count >> 32)); } cryptoid = sav->tdb_cryptoid; if (SAV_ISCTRORGCM(sav)) @@ -801,13 +849,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 +900,48 @@ 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) { + crp->crp_aad_length += 4; + 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, 4, crp->crp_aad); + + /* ESN */ + bcopy(&seqh, (char *)crp->crp_aad + 4, 4); + + /* Rest of aad */ + if (crp->crp_aad_length - 8 > 0) + m_copydata(m, skip + 4, crp->crp_aad_length - 4, + (char *)crp->crp_aad + 8); + } else + crp->crp_aad_start = skip; + + if (csp->csp_flags & CSP_F_ESN && sav->replay != NULL) + memcpy(crp->crp_esn, &seqh, 4); + 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 +996,10 @@ goto bad; } free(xd, M_XDATA); + if (crp->crp_aad) { + free(crp->crp_aad, M_XDATA); + crp->crp_aad = NULL; + } crypto_freereq(crp); ESPSTAT_INC(esps_hist[sav->alg_enc]); if (sav->tdb_authalgxform != NULL) @@ -951,6 +1033,8 @@ bad: CURVNET_RESTORE(); free(xd, M_XDATA); + if (crp->crp_aad) + free(crp->crp_aad, M_XDATA); crypto_freereq(crp); key_freesav(&sav); key_freesp(&sp);