Changeset View
Changeset View
Standalone View
Standalone View
sys/netipsec/xform_ah.c
Show First 20 Lines • Show All 102 Lines • ▼ Show 20 Lines | |||||
SYSCTL_INT(_net_inet_ah, OID_AUTO, ah_enable, | SYSCTL_INT(_net_inet_ah, OID_AUTO, ah_enable, | ||||
CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ah_enable), 0, ""); | CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ah_enable), 0, ""); | ||||
SYSCTL_INT(_net_inet_ah, OID_AUTO, ah_cleartos, | SYSCTL_INT(_net_inet_ah, OID_AUTO, ah_cleartos, | ||||
CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ah_cleartos), 0, ""); | CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ah_cleartos), 0, ""); | ||||
SYSCTL_VNET_PCPUSTAT(_net_inet_ah, IPSECCTL_STATS, stats, struct ahstat, | SYSCTL_VNET_PCPUSTAT(_net_inet_ah, IPSECCTL_STATS, stats, struct ahstat, | ||||
ahstat, "AH statistics (struct ahstat, netipsec/ah_var.h)"); | ahstat, "AH statistics (struct ahstat, netipsec/ah_var.h)"); | ||||
#endif | #endif | ||||
static MALLOC_DEFINE(M_AH, "ah", "IPsec AH"); | |||||
static unsigned char ipseczeroes[256]; /* larger than an ip6 extension hdr */ | static unsigned char ipseczeroes[256]; /* larger than an ip6 extension hdr */ | ||||
static int ah_input_cb(struct cryptop*); | static int ah_input_cb(struct cryptop*); | ||||
static int ah_output_cb(struct cryptop*); | static int ah_output_cb(struct cryptop*); | ||||
int | int | ||||
xform_ah_authsize(const struct auth_hash *esph) | xform_ah_authsize(const struct auth_hash *esph) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 302 Lines • ▼ Show 20 Lines | case AF_INET6: /* Ugly... */ | ||||
/* Done with IPv6 header. */ | /* Done with IPv6 header. */ | ||||
m_copyback(m, 0, sizeof(struct ip6_hdr), (caddr_t) &ip6); | m_copyback(m, 0, sizeof(struct ip6_hdr), (caddr_t) &ip6); | ||||
/* Let's deal with the remaining headers (if any). */ | /* Let's deal with the remaining headers (if any). */ | ||||
if (skip - sizeof(struct ip6_hdr) > 0) { | if (skip - sizeof(struct ip6_hdr) > 0) { | ||||
if (m->m_len <= skip) { | if (m->m_len <= skip) { | ||||
ptr = (unsigned char *) malloc( | ptr = (unsigned char *) malloc( | ||||
skip - sizeof(struct ip6_hdr), | skip - sizeof(struct ip6_hdr), | ||||
M_XDATA, M_NOWAIT); | M_AH, M_NOWAIT); | ||||
if (ptr == NULL) { | if (ptr == NULL) { | ||||
DPRINTF(("%s: failed to allocate memory" | DPRINTF(("%s: failed to allocate memory" | ||||
"for IPv6 headers\n",__func__)); | "for IPv6 headers\n",__func__)); | ||||
m_freem(m); | m_freem(m); | ||||
return ENOBUFS; | return ENOBUFS; | ||||
} | } | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | for (off = 0; off < skip - sizeof(struct ip6_hdr);) | ||||
nxt = ip6e->ip6e_nxt; | nxt = ip6e->ip6e_nxt; | ||||
break; | break; | ||||
default: | default: | ||||
DPRINTF(("%s: unexpected IPv6 header type %d", | DPRINTF(("%s: unexpected IPv6 header type %d", | ||||
__func__, off)); | __func__, off)); | ||||
error6: | error6: | ||||
if (alloc) | if (alloc) | ||||
free(ptr, M_XDATA); | free(ptr, M_AH); | ||||
m_freem(m); | m_freem(m); | ||||
return EINVAL; | return EINVAL; | ||||
} | } | ||||
/* Copyback and free, if we allocated. */ | /* Copyback and free, if we allocated. */ | ||||
if (alloc) { | if (alloc) { | ||||
m_copyback(m, sizeof(struct ip6_hdr), | m_copyback(m, sizeof(struct ip6_hdr), | ||||
skip - sizeof(struct ip6_hdr), ptr); | skip - sizeof(struct ip6_hdr), ptr); | ||||
free(ptr, M_XDATA); | free(ptr, M_AH); | ||||
} | } | ||||
break; | break; | ||||
#endif /* INET6 */ | #endif /* INET6 */ | ||||
} | } | ||||
return 0; | return 0; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | if (crp == NULL) { | ||||
goto bad; | goto bad; | ||||
} | } | ||||
crp->crp_payload_start = 0; | crp->crp_payload_start = 0; | ||||
crp->crp_payload_length = m->m_pkthdr.len; | crp->crp_payload_length = m->m_pkthdr.len; | ||||
crp->crp_digest_start = skip + rplen; | crp->crp_digest_start = skip + rplen; | ||||
/* Allocate IPsec-specific opaque crypto info. */ | /* Allocate IPsec-specific opaque crypto info. */ | ||||
xd = malloc(sizeof(*xd) + skip + rplen + authsize, M_XDATA, | xd = malloc(sizeof(*xd) + skip + rplen + authsize, M_AH, | ||||
M_NOWAIT | M_ZERO); | M_NOWAIT | M_ZERO); | ||||
if (xd == NULL) { | if (xd == NULL) { | ||||
DPRINTF(("%s: failed to allocate xform_data\n", __func__)); | DPRINTF(("%s: failed to allocate xform_data\n", __func__)); | ||||
AHSTAT_INC(ahs_crypto); | AHSTAT_INC(ahs_crypto); | ||||
crypto_freereq(crp); | crypto_freereq(crp); | ||||
error = ENOBUFS; | error = ENOBUFS; | ||||
goto bad; | goto bad; | ||||
} | } | ||||
Show All 11 Lines | ah_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff) | ||||
hl = ah->ah_nxt; | hl = ah->ah_nxt; | ||||
/* "Massage" the packet headers for crypto processing. */ | /* "Massage" the packet headers for crypto processing. */ | ||||
error = ah_massage_headers(&m, sav->sah->saidx.dst.sa.sa_family, | error = ah_massage_headers(&m, sav->sah->saidx.dst.sa.sa_family, | ||||
skip, ahx->type, 0); | skip, ahx->type, 0); | ||||
if (error != 0) { | if (error != 0) { | ||||
/* NB: mbuf is free'd by ah_massage_headers */ | /* NB: mbuf is free'd by ah_massage_headers */ | ||||
AHSTAT_INC(ahs_hdrops); | AHSTAT_INC(ahs_hdrops); | ||||
free(xd, M_XDATA); | free(xd, M_AH); | ||||
crypto_freereq(crp); | crypto_freereq(crp); | ||||
key_freesav(&sav); | key_freesav(&sav); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* Crypto operation descriptor. */ | /* Crypto operation descriptor. */ | ||||
crp->crp_op = CRYPTO_OP_COMPUTE_DIGEST; | crp->crp_op = CRYPTO_OP_COMPUTE_DIGEST; | ||||
crp->crp_flags = CRYPTO_F_CBIFSYNC; | crp->crp_flags = CRYPTO_F_CBIFSYNC; | ||||
▲ Show 20 Lines • Show All 101 Lines • ▼ Show 20 Lines | if (timingsafe_bcmp(ptr + skip + rplen, calc, authsize)) { | ||||
error = EACCES; | error = EACCES; | ||||
goto bad; | goto bad; | ||||
} | } | ||||
/* Fix the Next Protocol field. */ | /* Fix the Next Protocol field. */ | ||||
((uint8_t *) ptr)[protoff] = nxt; | ((uint8_t *) ptr)[protoff] = nxt; | ||||
/* Copyback the saved (uncooked) network headers. */ | /* Copyback the saved (uncooked) network headers. */ | ||||
m_copyback(m, 0, skip, ptr); | m_copyback(m, 0, skip, ptr); | ||||
free(xd, M_XDATA), xd = NULL; /* No longer needed */ | free(xd, M_AH), xd = NULL; /* No longer needed */ | ||||
/* | /* | ||||
* Header is now authenticated. | * Header is now authenticated. | ||||
*/ | */ | ||||
m->m_flags |= M_AUTHIPHDR|M_AUTHIPDGM; | m->m_flags |= M_AUTHIPHDR|M_AUTHIPDGM; | ||||
/* | /* | ||||
* Update replay sequence number, if appropriate. | * Update replay sequence number, if appropriate. | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | #endif | ||||
return error; | return error; | ||||
bad: | bad: | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
if (sav) | if (sav) | ||||
key_freesav(&sav); | key_freesav(&sav); | ||||
if (m != NULL) | if (m != NULL) | ||||
m_freem(m); | m_freem(m); | ||||
if (xd != NULL) | if (xd != NULL) | ||||
free(xd, M_XDATA); | free(xd, M_AH); | ||||
if (crp != NULL) | if (crp != NULL) | ||||
crypto_freereq(crp); | crypto_freereq(crp); | ||||
return error; | return error; | ||||
} | } | ||||
/* | /* | ||||
* AH output routine, called by ipsec[46]_perform_request(). | * AH output routine, called by ipsec[46]_perform_request(). | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 136 Lines • ▼ Show 20 Lines | if (crp == NULL) { | ||||
goto bad; | goto bad; | ||||
} | } | ||||
crp->crp_payload_start = 0; | crp->crp_payload_start = 0; | ||||
crp->crp_payload_length = m->m_pkthdr.len; | crp->crp_payload_length = m->m_pkthdr.len; | ||||
crp->crp_digest_start = skip + rplen; | crp->crp_digest_start = skip + rplen; | ||||
/* Allocate IPsec-specific opaque crypto info. */ | /* Allocate IPsec-specific opaque crypto info. */ | ||||
xd = malloc(sizeof(struct xform_data) + skip, M_XDATA, | xd = malloc(sizeof(struct xform_data) + skip, M_AH, | ||||
M_NOWAIT | M_ZERO); | M_NOWAIT | M_ZERO); | ||||
if (xd == NULL) { | if (xd == NULL) { | ||||
crypto_freereq(crp); | crypto_freereq(crp); | ||||
DPRINTF(("%s: failed to allocate xform_data\n", __func__)); | DPRINTF(("%s: failed to allocate xform_data\n", __func__)); | ||||
AHSTAT_INC(ahs_crypto); | AHSTAT_INC(ahs_crypto); | ||||
error = ENOBUFS; | error = ENOBUFS; | ||||
goto bad; | goto bad; | ||||
} | } | ||||
Show All 37 Lines | #endif /* INET6 */ | ||||
prot = IPPROTO_AH; | prot = IPPROTO_AH; | ||||
m_copyback(m, protoff, sizeof(uint8_t), (caddr_t) &prot); | m_copyback(m, protoff, sizeof(uint8_t), (caddr_t) &prot); | ||||
/* "Massage" the packet headers for crypto processing. */ | /* "Massage" the packet headers for crypto processing. */ | ||||
error = ah_massage_headers(&m, sav->sah->saidx.dst.sa.sa_family, | error = ah_massage_headers(&m, sav->sah->saidx.dst.sa.sa_family, | ||||
skip, ahx->type, 1); | skip, ahx->type, 1); | ||||
if (error != 0) { | if (error != 0) { | ||||
m = NULL; /* mbuf was free'd by ah_massage_headers. */ | m = NULL; /* mbuf was free'd by ah_massage_headers. */ | ||||
free(xd, M_XDATA); | free(xd, M_AH); | ||||
crypto_freereq(crp); | crypto_freereq(crp); | ||||
goto bad; | goto bad; | ||||
} | } | ||||
/* Crypto operation descriptor. */ | /* Crypto operation descriptor. */ | ||||
crp->crp_op = CRYPTO_OP_COMPUTE_DIGEST; | crp->crp_op = CRYPTO_OP_COMPUTE_DIGEST; | ||||
crp->crp_flags = CRYPTO_F_CBIFSYNC; | crp->crp_flags = CRYPTO_F_CBIFSYNC; | ||||
crypto_use_mbuf(crp, m); | crypto_use_mbuf(crp, m); | ||||
▲ Show 20 Lines • Show All 75 Lines • ▼ Show 20 Lines | if (m == NULL) { | ||||
goto bad; | goto bad; | ||||
} | } | ||||
/* | /* | ||||
* Copy original headers (with the new protocol number) back | * Copy original headers (with the new protocol number) back | ||||
* in place. | * in place. | ||||
*/ | */ | ||||
m_copyback(m, 0, skip, ptr); | m_copyback(m, 0, skip, ptr); | ||||
free(xd, M_XDATA); | free(xd, M_AH); | ||||
crypto_freereq(crp); | crypto_freereq(crp); | ||||
AHSTAT_INC(ahs_hist[sav->alg_auth]); | AHSTAT_INC(ahs_hist[sav->alg_auth]); | ||||
#ifdef REGRESSION | #ifdef REGRESSION | ||||
/* Emulate man-in-the-middle attack when ipsec_integrity is TRUE. */ | /* Emulate man-in-the-middle attack when ipsec_integrity is TRUE. */ | ||||
if (V_ipsec_integrity) { | if (V_ipsec_integrity) { | ||||
int alen; | int alen; | ||||
/* | /* | ||||
* Corrupt HMAC if we want to test integrity verification of | * Corrupt HMAC if we want to test integrity verification of | ||||
* the other side. | * the other side. | ||||
*/ | */ | ||||
alen = AUTHSIZE(sav); | alen = AUTHSIZE(sav); | ||||
m_copyback(m, m->m_pkthdr.len - alen, alen, ipseczeroes); | m_copyback(m, m->m_pkthdr.len - alen, alen, ipseczeroes); | ||||
} | } | ||||
#endif | #endif | ||||
/* NB: m is reclaimed by ipsec_process_done. */ | /* NB: m is reclaimed by ipsec_process_done. */ | ||||
error = ipsec_process_done(m, sp, sav, idx); | error = ipsec_process_done(m, sp, sav, idx); | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
return (error); | return (error); | ||||
bad: | bad: | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
free(xd, M_XDATA); | free(xd, M_AH); | ||||
crypto_freereq(crp); | crypto_freereq(crp); | ||||
key_freesav(&sav); | key_freesav(&sav); | ||||
key_freesp(&sp); | key_freesp(&sp); | ||||
return (error); | return (error); | ||||
} | } | ||||
static struct xformsw ah_xformsw = { | static struct xformsw ah_xformsw = { | ||||
.xf_type = XF_AH, | .xf_type = XF_AH, | ||||
Show All 11 Lines |