Changeset View
Changeset View
Standalone View
Standalone View
netipsec/ipsec.c
Show First 20 Lines • Show All 245 Lines • ▼ Show 20 Lines | |||||
static void ipsec4_get_ulp(const struct mbuf *m, struct secpolicyindex *, int); | static void ipsec4_get_ulp(const struct mbuf *m, struct secpolicyindex *, int); | ||||
static int ipsec4_setspidx_ipaddr(const struct mbuf *, struct secpolicyindex *); | static int ipsec4_setspidx_ipaddr(const struct mbuf *, struct secpolicyindex *); | ||||
#ifdef INET6 | #ifdef INET6 | ||||
static void ipsec6_get_ulp(const struct mbuf *m, struct secpolicyindex *, int); | static void ipsec6_get_ulp(const struct mbuf *m, struct secpolicyindex *, int); | ||||
static int ipsec6_setspidx_ipaddr(const struct mbuf *, struct secpolicyindex *); | static int ipsec6_setspidx_ipaddr(const struct mbuf *, struct secpolicyindex *); | ||||
#endif | #endif | ||||
static void ipsec_delpcbpolicy(struct inpcbpolicy *); | static void ipsec_delpcbpolicy(struct inpcbpolicy *); | ||||
static struct secpolicy *ipsec_deepcopy_policy(struct secpolicy *src); | static struct secpolicy *ipsec_deepcopy_policy(struct secpolicy *src); | ||||
static void vshiftl(unsigned char *, int, int); | |||||
MALLOC_DEFINE(M_IPSEC_INPCB, "inpcbpolicy", "inpcb-resident ipsec policy"); | MALLOC_DEFINE(M_IPSEC_INPCB, "inpcbpolicy", "inpcb-resident ipsec policy"); | ||||
/* | /* | ||||
* Return a held reference to the default SP. | * Return a held reference to the default SP. | ||||
*/ | */ | ||||
static struct secpolicy * | static struct secpolicy * | ||||
key_allocsp_default(const char* where, int tag) | key_allocsp_default(const char* where, int tag) | ||||
▲ Show 20 Lines • Show All 1,208 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Check the variable replay window. | * Check the variable replay window. | ||||
* ipsec_chkreplay() performs replay check before ICV verification. | * ipsec_chkreplay() performs replay check before ICV verification. | ||||
* ipsec_updatereplay() updates replay bitmap. This must be called after | * ipsec_updatereplay() updates replay bitmap. This must be called after | ||||
* ICV verification (it also performs replay check, which is usually done | * ICV verification (it also performs replay check, which is usually done | ||||
* beforehand). | * beforehand). | ||||
* 0 (zero) is returned if packet disallowed, 1 if packet permitted. | * 0 (zero) is returned if packet disallowed, 1 if packet permitted. | ||||
* | * | ||||
* Based on RFC 2401. | * Based on RFC 6479. Blocks are 32 bits unsigned integers | ||||
*/ | */ | ||||
#define IPSEC_BITMAP_INDEX_MASK(w) (w - 1) | |||||
#define IPSEC_REDUNDANT_BIT_SHIFTS 5 | |||||
#define IPSEC_REDUNDANT_BITS (1 << IPSEC_REDUNDANT_BIT_SHIFTS) | |||||
#define IPSEC_BITMAP_LOC_MASK (IPSEC_REDUNDANT_BITS - 1) | |||||
int | int | ||||
ipsec_chkreplay(u_int32_t seq, struct secasvar *sav) | ipsec_chkreplay(u_int32_t seq, struct secasvar *sav) | ||||
{ | { | ||||
const struct secreplay *replay; | const struct secreplay *replay; | ||||
u_int32_t diff; | u_int32_t wsizeb; /* Constant: window size. */ | ||||
int fr; | int ret, index, bit_location; | ||||
u_int32_t wsizeb; /* Constant: bits of window size. */ | |||||
int frlast; /* Constant: last frame. */ | |||||
IPSEC_ASSERT(sav != NULL, ("Null SA")); | IPSEC_ASSERT(sav != NULL, ("Null SA")); | ||||
IPSEC_ASSERT(sav->replay != NULL, ("Null replay state")); | IPSEC_ASSERT(sav->replay != NULL, ("Null replay state")); | ||||
SECASVAR_LOCK(sav); | |||||
ae: I'd prefer to move this lock acquire/release into xform_xxx code. This will allow to reduce the… | |||||
emeric.poupon_stormshield.euAuthorUnsubmitted Not Done Inline ActionsI am not sure to understand, what did you mean exactly? emeric.poupon_stormshield.eu: I am not sure to understand, what did you mean exactly? | |||||
aeUnsubmitted Not Done Inline ActionsDo not pay attention. I will start publish the code next week, so you will see what I mean. ae: Do not pay attention. I will start publish the code next week, so you will see what I mean. | |||||
ret = 0; | |||||
replay = sav->replay; | replay = sav->replay; | ||||
/* No need to check replay if disabled. */ | |||||
if (replay->wsize == 0) | if (replay->wsize == 0) | ||||
return (1); /* No need to check replay. */ | goto allowed; | ||||
/* Constant. */ | /* Constant. */ | ||||
frlast = replay->wsize - 1; | |||||
wsizeb = replay->wsize << 3; | wsizeb = replay->wsize << 3; | ||||
/* Sequence number of 0 is invalid. */ | /* Sequence number of 0 is invalid. */ | ||||
if (seq == 0) | if (seq == 0) | ||||
return (0); | goto end; | ||||
/* First time is always okay. */ | /* First time is always okay. */ | ||||
if (replay->count == 0) | if (replay->count == 0) | ||||
return (1); | goto allowed; | ||||
if (seq > replay->lastseq) { | |||||
/* Larger sequences are okay. */ | /* Larger sequences are okay. */ | ||||
return (1); | if (seq > replay->lastseq) | ||||
} else { | goto allowed; | ||||
/* seq is equal or less than lastseq. */ | |||||
diff = replay->lastseq - seq; | |||||
/* Over range to check, i.e. too old or wrapped. */ | /* Over range to check, i.e. too old or wrapped. */ | ||||
if (diff >= wsizeb) | if (replay->lastseq - seq >= wsizeb) | ||||
return (0); | goto end; | ||||
fr = frlast - diff / 8; | /* The sequence is inside the sliding window | ||||
* now check the bit in the bitmap | |||||
* bit location only depends on the sequence number | |||||
*/ | |||||
bit_location = seq & IPSEC_BITMAP_LOC_MASK; | |||||
index = (seq >> IPSEC_REDUNDANT_BIT_SHIFTS) | |||||
& IPSEC_BITMAP_INDEX_MASK(replay->bitmap_size); | |||||
/* This packet already seen? */ | /* This packet already seen? */ | ||||
if ((replay->bitmap)[fr] & (1 << (diff % 8))) | if ((replay->bitmap)[index] & (1 << bit_location)) | ||||
return (0); | goto end; | ||||
/* Out of order but good. */ | allowed: | ||||
return (1); | ret = 1; | ||||
end: | |||||
SECASVAR_UNLOCK(sav); | |||||
return (ret); | |||||
} | } | ||||
} | |||||
/* | /* | ||||
* Check replay counter whether to update or not. | * Check replay counter whether to update or not. | ||||
* OUT: 0: OK | * OUT: 0: OK | ||||
* 1: NG | * 1: NG | ||||
*/ | */ | ||||
int | int | ||||
ipsec_updatereplay(u_int32_t seq, struct secasvar *sav) | ipsec_updatereplay(u_int32_t seq, struct secasvar *sav) | ||||
{ | { | ||||
char buf[128]; | char buf[128]; | ||||
struct secreplay *replay; | struct secreplay *replay; | ||||
u_int32_t diff; | u_int32_t wsizeb; /* Constant: window size. */ | ||||
int fr; | int ret, diff, index, bit_location; | ||||
u_int32_t wsizeb; /* Constant: bits of window size. */ | |||||
int frlast; /* Constant: last frame. */ | |||||
IPSEC_ASSERT(sav != NULL, ("Null SA")); | IPSEC_ASSERT(sav != NULL, ("Null SA")); | ||||
IPSEC_ASSERT(sav->replay != NULL, ("Null replay state")); | IPSEC_ASSERT(sav->replay != NULL, ("Null replay state")); | ||||
SECASVAR_LOCK(sav); | |||||
aeUnsubmitted Not Done Inline ActionsThe same... ae: The same... | |||||
ret = 1; | |||||
replay = sav->replay; | replay = sav->replay; | ||||
if (replay->wsize == 0) | if (replay->wsize == 0) | ||||
goto ok; /* No need to check replay. */ | goto ok; /* No need to check replay. */ | ||||
/* Constant. */ | /* Constant. */ | ||||
frlast = replay->wsize - 1; | |||||
wsizeb = replay->wsize << 3; | wsizeb = replay->wsize << 3; | ||||
/* Sequence number of 0 is invalid. */ | /* Sequence number of 0 is invalid. */ | ||||
if (seq == 0) | if (seq == 0) | ||||
return (1); | goto end; | ||||
/* First time. */ | /* The packet is too old, no need to update */ | ||||
if (replay->count == 0) { | if (wsizeb + seq < replay->lastseq) | ||||
replay->lastseq = seq; | |||||
bzero(replay->bitmap, replay->wsize); | |||||
(replay->bitmap)[frlast] = 1; | |||||
goto ok; | goto ok; | ||||
} | |||||
/* Now update the bit */ | |||||
index = (seq >> IPSEC_REDUNDANT_BIT_SHIFTS); | |||||
/* First check if the sequence number is in the range */ | |||||
if (seq > replay->lastseq) { | if (seq > replay->lastseq) { | ||||
/* seq is larger than lastseq. */ | int id; | ||||
diff = seq - replay->lastseq; | int index_cur = replay->lastseq >> IPSEC_REDUNDANT_BIT_SHIFTS; | ||||
/* New larger sequence number. */ | diff = index - index_cur; | ||||
if (diff < wsizeb) { | if (diff > replay->bitmap_size) { | ||||
/* In window. */ | /* something unusual in this case */ | ||||
/* Set bit for this packet. */ | diff = replay->bitmap_size; | ||||
vshiftl(replay->bitmap, diff, replay->wsize); | |||||
(replay->bitmap)[frlast] |= 1; | |||||
} else { | |||||
/* This packet has a "way larger". */ | |||||
bzero(replay->bitmap, replay->wsize); | |||||
(replay->bitmap)[frlast] = 1; | |||||
} | } | ||||
replay->lastseq = seq; | |||||
/* Larger is good. */ | for (id = 0; id < diff; ++id) { | ||||
} else { | replay->bitmap[(id + index_cur + 1) | ||||
/* seq is equal or less than lastseq. */ | & IPSEC_BITMAP_INDEX_MASK(replay->bitmap_size)] = 0; | ||||
diff = replay->lastseq - seq; | } | ||||
/* Over range to check, i.e. too old or wrapped. */ | replay->lastseq = seq; | ||||
if (diff >= wsizeb) | } | ||||
return (1); | |||||
fr = frlast - diff / 8; | index &= IPSEC_BITMAP_INDEX_MASK(replay->bitmap_size); | ||||
bit_location = seq & IPSEC_BITMAP_LOC_MASK; | |||||
/* This packet already seen? */ | /* this packet has already been received */ | ||||
if ((replay->bitmap)[fr] & (1 << (diff % 8))) | if (replay->bitmap[index] & (1 << bit_location)) | ||||
return (1); | goto end; | ||||
/* Mark as seen. */ | replay->bitmap[index] |= (1 << bit_location); | ||||
(replay->bitmap)[fr] |= (1 << (diff % 8)); | |||||
/* Out of order but good. */ | |||||
} | |||||
ok: | ok: | ||||
if (replay->count == ~0) { | if (replay->count == ~0) { | ||||
/* Set overflow flag. */ | /* Set overflow flag. */ | ||||
replay->overflow++; | replay->overflow++; | ||||
/* Don't increment, no more packets accepted. */ | /* Don't increment, no more packets accepted. */ | ||||
if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) | if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) | ||||
return (1); | goto end; | ||||
ipseclog((LOG_WARNING, "%s: replay counter made %d cycle. %s\n", | ipseclog((LOG_WARNING, "%s: replay counter made %d cycle. %s\n", | ||||
__func__, replay->overflow, | __func__, replay->overflow, | ||||
ipsec_logsastr(sav, buf, sizeof(buf)))); | ipsec_logsastr(sav, buf, sizeof(buf)))); | ||||
} | } | ||||
replay->count++; | ret = 0; | ||||
return (0); | end: | ||||
} | SECASVAR_UNLOCK(sav); | ||||
return (ret); | |||||
/* | |||||
* Shift variable length buffer to left. | |||||
* IN: bitmap: pointer to the buffer | |||||
* nbit: the number of to shift. | |||||
* wsize: buffer size (bytes). | |||||
*/ | |||||
static void | |||||
vshiftl(unsigned char *bitmap, int nbit, int wsize) | |||||
{ | |||||
int s, j, i; | |||||
unsigned char over; | |||||
for (j = 0; j < nbit; j += 8) { | |||||
s = (nbit - j < 8) ? (nbit - j): 8; | |||||
bitmap[0] <<= s; | |||||
for (i = 1; i < wsize; i++) { | |||||
over = (bitmap[i] >> (8 - s)); | |||||
bitmap[i] <<= s; | |||||
bitmap[i-1] |= over; | |||||
} | |||||
} | |||||
} | } | ||||
/* Return a printable string for the address. */ | /* Return a printable string for the address. */ | ||||
char* | char* | ||||
ipsec_address(union sockaddr_union* sa, char *buf, socklen_t size) | ipsec_address(union sockaddr_union* sa, char *buf, socklen_t size) | ||||
{ | { | ||||
switch (sa->sa.sa_family) { | switch (sa->sa.sa_family) { | ||||
▲ Show 20 Lines • Show All 94 Lines • Show Last 20 Lines |
I'd prefer to move this lock acquire/release into xform_xxx code. This will allow to reduce the number of its acquiring and also reduce conflicts with my oncoming changes :)