diff options
author | ume <ume@FreeBSD.org> | 2001-06-11 12:39:29 +0000 |
---|---|---|
committer | ume <ume@FreeBSD.org> | 2001-06-11 12:39:29 +0000 |
commit | 832f8d224926758a9ae0b23a6b45353e44fbc87a (patch) | |
tree | a79fc7ad2b97862c4a404f352f0211ad93a7b5f1 /sys/netkey | |
parent | 2693854b01a52b0395a91322aa3edf926bddff38 (diff) | |
download | FreeBSD-src-832f8d224926758a9ae0b23a6b45353e44fbc87a.zip FreeBSD-src-832f8d224926758a9ae0b23a6b45353e44fbc87a.tar.gz |
Sync with recent KAME.
This work was based on kame-20010528-freebsd43-snap.tgz and some
critical problem after the snap was out were fixed.
There are many many changes since last KAME merge.
TODO:
- The definitions of SADB_* in sys/net/pfkeyv2.h are still different
from RFC2407/IANA assignment because of binary compatibility
issue. It should be fixed under 5-CURRENT.
- ip6po_m member of struct ip6_pktopts is no longer used. But, it
is still there because of binary compatibility issue. It should
be removed under 5-CURRENT.
Reviewed by: itojun
Obtained from: KAME
MFC after: 3 weeks
Diffstat (limited to 'sys/netkey')
-rw-r--r-- | sys/netkey/key.c | 975 | ||||
-rw-r--r-- | sys/netkey/key.h | 7 | ||||
-rw-r--r-- | sys/netkey/key_debug.c | 7 | ||||
-rw-r--r-- | sys/netkey/key_debug.h | 9 | ||||
-rw-r--r-- | sys/netkey/key_var.h | 39 | ||||
-rw-r--r-- | sys/netkey/keydb.h | 13 | ||||
-rw-r--r-- | sys/netkey/keysock.c | 19 |
7 files changed, 799 insertions, 270 deletions
diff --git a/sys/netkey/key.c b/sys/netkey/key.c index 497695a..31dc63b 100644 --- a/sys/netkey/key.c +++ b/sys/netkey/key.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: key.c,v 1.137 2000/06/24 00:47:07 itojun Exp $ */ +/* $KAME: key.c,v 1.187 2001/05/24 07:41:22 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -79,11 +79,7 @@ #include <netkey/keydb.h> #include <netkey/key.h> #include <netkey/keysock.h> -#ifdef IPSEC_DEBUG #include <netkey/key_debug.h> -#else -#define KEYDEBUG(lev,arg) -#endif #include <netinet6/ipsec.h> #ifdef INET6 @@ -100,9 +96,15 @@ #endif #endif #include <netinet6/ipcomp.h> +#ifdef INET6 +#include <netinet6/ipcomp6.h> +#endif #include <machine/stdarg.h> +/* randomness */ +#include <sys/random.h> + #include <net/net_osdep.h> #ifndef satosin @@ -208,6 +210,10 @@ static const int maxsize[] = { sizeof(struct sadb_x_sa2), /* SADB_X_SA2 */ }; +static int ipsec_esp_keymin = 256; +static int ipsec_esp_auth = 0; +static int ipsec_ah_keymin = 128; + #ifdef SYSCTL_DECL SYSCTL_DECL(_net_key); #endif @@ -245,9 +251,13 @@ SYSCTL_INT(_net_key, KEYCTL_BLOCKACQ_COUNT, blockacq_count, CTLFLAG_RW, \ SYSCTL_INT(_net_key, KEYCTL_BLOCKACQ_LIFETIME, blockacq_lifetime, CTLFLAG_RW, \ &key_blockacq_lifetime, 0, ""); -static const int ipsec_esp_keymin = 256; -static const int ipsec_esp_auth = 0; -static const int ipsec_ah_keymin = 128; +/* minimum ESP key length */ +SYSCTL_INT(_net_key, KEYCTL_ESP_KEYMIN, esp_keymin, CTLFLAG_RW, \ + &ipsec_esp_keymin, 0, ""); + +/* minimum AH key length */ +SYSCTL_INT(_net_key, KEYCTL_AH_KEYMIN, ah_keymin, CTLFLAG_RW, \ + &ipsec_ah_keymin, 0, ""); #ifndef LIST_FOREACH #define LIST_FOREACH(elm, head, field) \ @@ -371,6 +381,7 @@ static int key_spddump __P((struct socket *, struct mbuf *, static struct mbuf *key_setdumpsp __P((struct secpolicy *, u_int8_t, u_int32_t, u_int32_t)); static u_int key_getspreqmsglen __P((struct secpolicy *)); +static int key_spdexpire __P((struct secpolicy *)); static struct secashead *key_newsah __P((struct secasindex *)); static void key_delsah __P((struct secashead *)); static struct secasvar *key_newsav __P((struct mbuf *, @@ -404,6 +415,8 @@ static int key_cmpsaidx_exactly __P((struct secasindex *, struct secasindex *)); static int key_cmpsaidx_withmode __P((struct secasindex *, struct secasindex *)); +static int key_cmpsaidx_withoutmode2 + __P((struct secasindex *, struct secasindex *)); static int key_cmpsaidx_withoutmode __P((struct secasindex *, struct secasindex *)); static int key_cmpspidx_exactly @@ -413,7 +426,6 @@ static int key_cmpspidx_withmask static int key_sockaddrcmp __P((struct sockaddr *, struct sockaddr *, int)); static int key_bbcmp __P((caddr_t, caddr_t, u_int)); static void key_srandom __P((void)); -static u_long key_random __P((void)); static u_int16_t key_satype2proto __P((u_int8_t)); static u_int8_t key_proto2satype __P((u_int16_t)); @@ -437,10 +449,12 @@ static int key_delete __P((struct socket *, struct mbuf *, static int key_get __P((struct socket *, struct mbuf *, const struct sadb_msghdr *)); +static void key_getcomb_setlifetime __P((struct sadb_comb *)); #ifdef IPSEC_ESP static struct mbuf *key_getcomb_esp __P((void)); #endif static struct mbuf *key_getcomb_ah __P((void)); +static struct mbuf *key_getcomb_ipcomp __P((void)); static struct mbuf *key_getprop __P((const struct secasindex *)); static int key_acquire __P((struct secasindex *, struct secpolicy *)); @@ -485,6 +499,7 @@ key_allocsp(spidx, dir) u_int dir; { struct secpolicy *sp; + struct timeval tv; int s; /* sanity check */ @@ -525,6 +540,8 @@ found: KEY_CHKSPDIR(sp->spidx.dir, dir, "key_allocsp"); /* found a SPD entry */ + microtime(&tv); + sp->lastused = tv.tv_sec; sp->refcnt++; splx(s); KEYDEBUG(KEYDEBUG_IPSEC_STAMP, @@ -535,8 +552,75 @@ found: } /* - * allocating a SA entry for a *OUTBOUND* packet. - * checking each request entries in SP, and acquire SA if need. + * return a policy that matches this particular inbound packet. + * XXX slow + */ +struct secpolicy * +key_gettunnel(osrc, odst, isrc, idst) + struct sockaddr *osrc, *odst, *isrc, *idst; +{ + struct secpolicy *sp; + const int dir = IPSEC_DIR_INBOUND; + struct timeval tv; + int s; + struct ipsecrequest *r1, *r2, *p; + struct sockaddr *os, *od, *is, *id; + struct secpolicyindex spidx; + + s = splnet(); /*called from softclock()*/ + LIST_FOREACH(sp, &sptree[dir], chain) { + if (sp->state == IPSEC_SPSTATE_DEAD) + continue; + + r1 = r2 = NULL; + for (p = sp->req; p; p = p->next) { + if (p->saidx.mode != IPSEC_MODE_TUNNEL) + continue; + + r1 = r2; + r2 = p; + + if (!r1) { + /* here we look at address matches only */ + spidx = sp->spidx; + if (isrc->sa_len > sizeof(spidx.src) || + idst->sa_len > sizeof(spidx.dst)) + continue; + bcopy(isrc, &spidx.src, isrc->sa_len); + bcopy(idst, &spidx.dst, idst->sa_len); + if (!key_cmpspidx_withmask(&sp->spidx, &spidx)) + continue; + } else { + is = (struct sockaddr *)&r1->saidx.src; + id = (struct sockaddr *)&r1->saidx.dst; + if (key_sockaddrcmp(is, isrc, 0) || + key_sockaddrcmp(id, idst, 0)) + continue; + } + + os = (struct sockaddr *)&r2->saidx.src; + od = (struct sockaddr *)&r2->saidx.dst; + if (key_sockaddrcmp(os, osrc, 0) || + key_sockaddrcmp(od, odst, 0)) + continue; + + goto found; + } + } + splx(s); + return NULL; + +found: + microtime(&tv); + sp->lastused = tv.tv_sec; + sp->refcnt++; + splx(s); + return sp; +} + +/* + * allocating an SA entry for an *OUTBOUND* packet. + * checking each request entries in SP, and acquire an SA if need. * OUT: 0: there are valid requests. * ENOENT: policy may be valid, but SA with REQUIRE is on acquiring. */ @@ -987,7 +1071,7 @@ key_freesav(sav) sav->refcnt--; KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP freesav cause refcnt--:%d SA:%p SPI %d\n", + printf("DP freesav cause refcnt--:%d SA:%p SPI %u\n", sav->refcnt, sav, (u_int32_t)ntohl(sav->spi))); if (sav->refcnt == 0) @@ -1212,9 +1296,7 @@ key_msg2sp(xpl0, len, error) switch (xisr->sadb_x_ipsecrequest_proto) { case IPPROTO_ESP: case IPPROTO_AH: -#if 1 /*nonstandard*/ case IPPROTO_IPCOMP: -#endif break; default: #ifdef IPSEC_DEBUG @@ -1534,11 +1616,11 @@ fail: /* * SADB_X_SPDADD, SADB_X_SPDSETIDX or SADB_X_SPDUPDATE processing * add a entry to SP database, when received - * <base, address(SD), policy> + * <base, address(SD), (lifetime(H),) policy> * from the user(?). * Adding to SP database, * and send - * <base, address(SD), policy> + * <base, address(SD), (lifetime(H),) policy> * to the socket which was send. * * SPDADD set a unique policy entry. @@ -1555,8 +1637,10 @@ key_spdadd(so, m, mhp) { struct sadb_address *src0, *dst0; struct sadb_x_policy *xpl0, *xpl; + struct sadb_lifetime *lft = NULL; struct secpolicyindex spidx; struct secpolicy *newsp; + struct timeval tv; int error; /* sanity check */ @@ -1579,6 +1663,16 @@ key_spdadd(so, m, mhp) #endif return key_senderror(so, m, EINVAL); } + if (mhp->ext[SADB_EXT_LIFETIME_HARD] != NULL) { + if (mhp->extlen[SADB_EXT_LIFETIME_HARD] + < sizeof(struct sadb_lifetime)) { +#ifdef IPSEC_DEBUG + printf("key_spdadd: invalid message is passed.\n"); +#endif + return key_senderror(so, m, EINVAL); + } + lft = (struct sadb_lifetime *)mhp->ext[SADB_EXT_LIFETIME_HARD]; + } src0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_SRC]; dst0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST]; @@ -1702,6 +1796,12 @@ key_spdadd(so, m, mhp) } #endif + microtime(&tv); + newsp->created = tv.tv_sec; + newsp->lastused = tv.tv_sec; + newsp->lifetime = lft ? lft->sadb_lifetime_addtime : 0; + newsp->validtime = lft ? lft->sadb_lifetime_usetime : 0; + newsp->refcnt = 1; /* do not reclaim until I say I do */ newsp->state = IPSEC_SPSTATE_ALIVE; LIST_INSERT_TAIL(&sptree[newsp->spidx.dir], newsp, secpolicy, chain); @@ -1710,8 +1810,9 @@ key_spdadd(so, m, mhp) if (mhp->msg->sadb_msg_type == SADB_X_SPDUPDATE) { struct secspacq *spacq; if ((spacq = key_getspacq(&spidx)) != NULL) { - /* reset counter in order to deletion by timehander. */ - spacq->tick = key_blockacq_lifetime; + /* reset counter in order to deletion by timehandler. */ + microtime(&tv); + spacq->created = tv.tv_sec; spacq->count = 0; } } @@ -1722,8 +1823,15 @@ key_spdadd(so, m, mhp) int off; /* create new sadb_msg to reply. */ - n = key_gather_mbuf(m, mhp, 2, 4, SADB_EXT_RESERVED, - SADB_X_EXT_POLICY, SADB_EXT_ADDRESS_SRC, SADB_EXT_ADDRESS_DST); + if (lft) { + n = key_gather_mbuf(m, mhp, 2, 4, SADB_EXT_RESERVED, + SADB_X_EXT_POLICY, SADB_EXT_LIFETIME_HARD, + SADB_EXT_ADDRESS_SRC, SADB_EXT_ADDRESS_DST); + } else { + n = key_gather_mbuf(m, mhp, 2, 4, SADB_EXT_RESERVED, + SADB_X_EXT_POLICY, + SADB_EXT_ADDRESS_SRC, SADB_EXT_ADDRESS_DST); + } if (!n) return key_senderror(so, m, ENOBUFS); @@ -2308,6 +2416,123 @@ key_getspreqmsglen(sp) return tlen; } +/* + * SADB_SPDEXPIRE processing + * send + * <base, address(SD), lifetime(CH), policy> + * to KMD by PF_KEY. + * + * OUT: 0 : succeed + * others : error number + */ +static int +key_spdexpire(sp) + struct secpolicy *sp; +{ + int s; + struct mbuf *result = NULL, *m; + int len; + int error = -1; + struct sadb_lifetime *lt; + + /* XXX: Why do we lock ? */ + s = splnet(); /*called from softclock()*/ + + /* sanity check */ + if (sp == NULL) + panic("key_spdexpire: NULL pointer is passed.\n"); + + /* set msg header */ + m = key_setsadbmsg(SADB_X_SPDEXPIRE, 0, 0, 0, 0, 0); + if (!m) { + error = ENOBUFS; + goto fail; + } + result = m; + + /* create lifetime extension (current and hard) */ + len = PFKEY_ALIGN8(sizeof(*lt)) * 2; + m = key_alloc_mbuf(len); + if (!m || m->m_next) { /*XXX*/ + if (m) + m_freem(m); + error = ENOBUFS; + goto fail; + } + bzero(mtod(m, caddr_t), len); + lt = mtod(m, struct sadb_lifetime *); + lt->sadb_lifetime_len = PFKEY_UNIT64(sizeof(struct sadb_lifetime)); + lt->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT; + lt->sadb_lifetime_allocations = 0; + lt->sadb_lifetime_bytes = 0; + lt->sadb_lifetime_addtime = sp->created; + lt->sadb_lifetime_usetime = sp->lastused; + lt = (struct sadb_lifetime *)(mtod(m, caddr_t) + len / 2); + lt->sadb_lifetime_len = PFKEY_UNIT64(sizeof(struct sadb_lifetime)); + lt->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD; + lt->sadb_lifetime_allocations = 0; + lt->sadb_lifetime_bytes = 0; + lt->sadb_lifetime_addtime = sp->lifetime; + lt->sadb_lifetime_usetime = sp->validtime; + m_cat(result, m); + + /* set sadb_address for source */ + m = key_setsadbaddr(SADB_EXT_ADDRESS_SRC, + (struct sockaddr *)&sp->spidx.src, + sp->spidx.prefs, sp->spidx.ul_proto); + if (!m) { + error = ENOBUFS; + goto fail; + } + m_cat(result, m); + + /* set sadb_address for destination */ + m = key_setsadbaddr(SADB_EXT_ADDRESS_DST, + (struct sockaddr *)&sp->spidx.dst, + sp->spidx.prefd, sp->spidx.ul_proto); + if (!m) { + error = ENOBUFS; + goto fail; + } + m_cat(result, m); + + /* set secpolicy */ + m = key_sp2msg(sp); + if (!m) { + error = ENOBUFS; + goto fail; + } + m_cat(result, m); + + if ((result->m_flags & M_PKTHDR) == 0) { + error = EINVAL; + goto fail; + } + + if (result->m_len < sizeof(struct sadb_msg)) { + result = m_pullup(result, sizeof(struct sadb_msg)); + if (result == NULL) { + error = ENOBUFS; + goto fail; + } + } + + result->m_pkthdr.len = 0; + for (m = result; m; m = m->m_next) + result->m_pkthdr.len += m->m_len; + + mtod(result, struct sadb_msg *)->sadb_msg_len = + PFKEY_UNIT64(result->m_pkthdr.len); + + return key_sendup_mbuf(NULL, result, KEY_SENDUP_REGISTERED); + + fail: + if (result) + m_freem(result); + splx(s); + return error; +} + /* %%% SAD management */ /* * allocating a memory for new SA head, and copy from the values of mhp. @@ -2484,8 +2709,12 @@ key_newsav(m, mhp, sah, errp) } } - /* reset tick */ - newsav->tick = 0; + /* reset created */ + { + struct timeval tv; + microtime(&tv); + newsav->created = tv.tv_sec; + } newsav->pid = mhp->msg->sadb_msg_pid; @@ -2517,28 +2746,41 @@ key_delsav(sav) if (__LIST_CHAINED(sav)) LIST_REMOVE(sav, chain); - if (sav->key_auth != NULL) + if (sav->key_auth != NULL) { + bzero(_KEYBUF(sav->key_auth), _KEYLEN(sav->key_auth)); KFREE(sav->key_auth); - if (sav->key_enc != NULL) + sav->key_auth = NULL; + } + if (sav->key_enc != NULL) { + bzero(_KEYBUF(sav->key_enc), _KEYLEN(sav->key_enc)); KFREE(sav->key_enc); - if (sav->replay != NULL) + sav->key_enc = NULL; + } + if (sav->sched) { + bzero(sav->sched, sav->schedlen); + KFREE(sav->sched); + sav->sched = NULL; + } + if (sav->replay != NULL) { keydb_delsecreplay(sav->replay); - if (sav->lft_c != NULL) + sav->replay = NULL; + } + if (sav->lft_c != NULL) { KFREE(sav->lft_c); - if (sav->lft_h != NULL) + sav->lft_c = NULL; + } + if (sav->lft_h != NULL) { KFREE(sav->lft_h); - if (sav->lft_s != NULL) + sav->lft_h = NULL; + } + if (sav->lft_s != NULL) { KFREE(sav->lft_s); - if (sav->iv != NULL) + sav->lft_s = NULL; + } + if (sav->iv != NULL) { KFREE(sav->iv); -#if notyet - if (sav->misc1 != NULL) - KFREE(sav->misc1); - if (sav->misc2 != NULL) - KFREE(sav->misc2); - if (sav->misc3 != NULL) - KFREE(sav->misc3); -#endif + sav->iv = NULL; + } KFREE(sav); @@ -2560,8 +2802,8 @@ key_getsah(saidx) LIST_FOREACH(sah, &sahtree, chain) { if (sah->state == SADB_SASTATE_DEAD) continue; - if (key_cmpsaidx_exactly(&sah->saidx, saidx)) - return(sah); + if (key_cmpsaidx_withoutmode2(&sah->saidx, saidx)) + return sah; } return NULL; @@ -2671,15 +2913,12 @@ key_setsaval(sav, m, mhp) sav->replay = NULL; sav->key_auth = NULL; sav->key_enc = NULL; + sav->sched = NULL; + sav->schedlen = 0; sav->iv = NULL; sav->lft_c = NULL; sav->lft_h = NULL; sav->lft_s = NULL; -#if notyet - sav->misc1 = NULL; - sav->misc2 = NULL; - sav->misc3 = NULL; -#endif /* SA */ if (mhp->ext[SADB_EXT_SA] != NULL) { @@ -2725,7 +2964,7 @@ key_setsaval(sav, m, mhp) case SADB_SATYPE_AH: case SADB_SATYPE_ESP: if (len == PFKEY_ALIGN8(sizeof(struct sadb_key)) && - sav->alg_auth != SADB_AALG_NULL) + sav->alg_auth != SADB_X_AALG_NULL) error = EINVAL; break; case SADB_X_SATYPE_IPCOMP: @@ -2766,11 +3005,26 @@ key_setsaval(sav, m, mhp) switch (mhp->msg->sadb_msg_satype) { case SADB_SATYPE_ESP: if (len == PFKEY_ALIGN8(sizeof(struct sadb_key)) && - sav->alg_enc != SADB_EALG_NULL) + sav->alg_enc != SADB_EALG_NULL) { error = EINVAL; + break; + } + sav->key_enc = (struct sadb_key *)key_newbuf(key0, len); + if (sav->key_enc == NULL) { +#ifdef IPSEC_DEBUG + printf("key_setsaval: No more memory.\n"); +#endif + error = ENOBUFS; + goto fail; + } break; - case SADB_SATYPE_AH: case SADB_X_SATYPE_IPCOMP: + if (len != PFKEY_ALIGN8(sizeof(struct sadb_key))) + error = EINVAL; + sav->key_enc = NULL; /*just in case*/ + break; + case SADB_SATYPE_AH: + default: error = EINVAL; break; } @@ -2780,15 +3034,6 @@ key_setsaval(sav, m, mhp) #endif goto fail; } - - sav->key_enc = (struct sadb_key *)key_newbuf(key0, len); - if (sav->key_enc == NULL) { -#ifdef IPSEC_DEBUG - printf("key_setsaval: No more memory.\n"); -#endif - error = ENOBUFS; - goto fail; - } } /* set iv */ @@ -2797,9 +3042,9 @@ key_setsaval(sav, m, mhp) switch (mhp->msg->sadb_msg_satype) { case SADB_SATYPE_ESP: #ifdef IPSEC_ESP - algo = &esp_algorithms[sav->alg_enc]; + algo = esp_algorithm_lookup(sav->alg_enc); if (algo && algo->ivlen) - sav->ivlen = (*algo->ivlen)(sav); + sav->ivlen = (*algo->ivlen)(algo, sav); if (sav->ivlen == 0) break; KMALLOC(sav->iv, caddr_t, sav->ivlen); @@ -2812,20 +3057,11 @@ key_setsaval(sav, m, mhp) } /* initialize */ - { - int i; - u_int8_t *p = (u_int8_t *)sav->iv; - for (i = 0; i < sav->ivlen; i++) - p[i] = key_random() & 0xff; - } - break; -#else - break; + key_randomfill(sav->iv, sav->ivlen); #endif + break; case SADB_SATYPE_AH: -#if 1 /*nonstandard*/ case SADB_X_SATYPE_IPCOMP: -#endif break; default: #ifdef IPSEC_DEBUG @@ -2835,8 +3071,9 @@ key_setsaval(sav, m, mhp) goto fail; } - /* reset tick */ - sav->tick = 0; + /* reset created */ + microtime(&tv); + sav->created = tv.tv_sec; /* make lifetime for CURRENT */ KMALLOC(sav->lft_c, struct sadb_lifetime *, @@ -2900,63 +3137,42 @@ key_setsaval(sav, m, mhp) } } -#if notyet - /* pre-processing for DES */ - switch (sav->alg_enc) { - case SADB_EALG_DESCBC: - if (des_key_sched((C_Block *)_KEYBUF(sav->key_enc), - (des_key_schedule)sav->misc1) != 0) { -#ifdef IPSEC_DEBUG - printf("key_setsaval: error des_key_sched.\n"); -#endif - sav->misc1 = NULL; - /* THROUGH */ - } - break; - case SADB_EALG_3DESCBC: - if (des_key_sched((C_Block *)_KEYBUF(sav->key_enc), - (des_key_schedule)sav->misc1) != 0 - || des_key_sched((C_Block *)(_KEYBUF(sav->key_enc) + 8), - (des_key_schedule)sav->misc2) != 0 - || des_key_sched((C_Block *)(_KEYBUF(sav->key_enc) + 16), - (des_key_schedule)sav->misc3) != 0) { -#ifdef IPSEC_DEBUG - printf("key_setsaval: error des_key_sched.\n"); -#endif - sav->misc1 = NULL; - sav->misc2 = NULL; - sav->misc3 = NULL; - /* THROUGH */ - } - } -#endif - return 0; fail: /* initialization */ - if (sav->replay != NULL) + if (sav->replay != NULL) { keydb_delsecreplay(sav->replay); - if (sav->key_auth != NULL) + sav->replay = NULL; + } + if (sav->key_auth != NULL) { KFREE(sav->key_auth); - if (sav->key_enc != NULL) + sav->key_auth = NULL; + } + if (sav->key_enc != NULL) { KFREE(sav->key_enc); - if (sav->iv != NULL) + sav->key_enc = NULL; + } + if (sav->sched) { + KFREE(sav->sched); + sav->sched = NULL; + } + if (sav->iv != NULL) { KFREE(sav->iv); - if (sav->lft_c != NULL) + sav->iv = NULL; + } + if (sav->lft_c != NULL) { KFREE(sav->lft_c); - if (sav->lft_h != NULL) + sav->lft_c = NULL; + } + if (sav->lft_h != NULL) { KFREE(sav->lft_h); - if (sav->lft_s != NULL) + sav->lft_h = NULL; + } + if (sav->lft_s != NULL) { KFREE(sav->lft_s); -#if notyet - if (sav->misc1 != NULL) - KFREE(sav->misc1); - if (sav->misc2 != NULL) - KFREE(sav->misc2); - if (sav->misc3 != NULL) - KFREE(sav->misc3); -#endif + sav->lft_s = NULL; + } return error; } @@ -2977,11 +3193,17 @@ key_mature(sav) mature = 0; /* check SPI value */ - if (ntohl(sav->spi) >= 0 && ntohl(sav->spi) <= 255) { + switch (sav->sah->saidx.proto) { + case IPPROTO_ESP: + case IPPROTO_AH: + if (ntohl(sav->spi) >= 0 && ntohl(sav->spi) <= 255) { #ifdef IPSEC_DEBUG - printf("key_mature: illegal range of SPI %d.\n", sav->spi); + printf("key_mature: illegal range of SPI %u.\n", + (u_int32_t)ntohl(sav->spi)); #endif - return EINVAL; + return EINVAL; + } + break; } /* check satype */ @@ -2996,7 +3218,10 @@ key_mature(sav) #endif return EINVAL; } - checkmask = 3; + if (sav->alg_auth == SADB_AALG_NONE) + checkmask = 1; + else + checkmask = 3; mustmask = 1; break; case IPPROTO_AH: @@ -3018,7 +3243,6 @@ key_mature(sav) checkmask = 2; mustmask = 2; break; -#if 1 /*nonstandard*/ case IPPROTO_IPCOMP: if (sav->alg_auth != SADB_AALG_NONE) { #ifdef IPSEC_DEBUG @@ -3037,7 +3261,6 @@ key_mature(sav) checkmask = 4; mustmask = 4; break; -#endif default: #ifdef IPSEC_DEBUG printf("key_mature: Invalid satype.\n"); @@ -3047,19 +3270,11 @@ key_mature(sav) /* check authentication algorithm */ if ((checkmask & 2) != 0) { - struct ah_algorithm *algo; + const struct ah_algorithm *algo; int keylen; - /* XXX: should use algorithm map to check. */ - switch (sav->alg_auth) { - case SADB_AALG_NONE: - case SADB_AALG_MD5HMAC: - case SADB_AALG_SHA1HMAC: - case SADB_AALG_MD5: - case SADB_AALG_SHA: - case SADB_AALG_NULL: - break; - default: + algo = ah_algorithm_lookup(sav->alg_auth); + if (!algo) { #ifdef IPSEC_DEBUG printf("key_mature: " "unknown authentication algorithm.\n"); @@ -3068,8 +3283,6 @@ key_mature(sav) } /* algorithm-dependent check */ - algo = &ah_algorithms[sav->alg_auth]; - if (sav->key_auth) keylen = sav->key_auth->sadb_key_bits; else @@ -3102,19 +3315,11 @@ key_mature(sav) /* check encryption algorithm */ if ((checkmask & 1) != 0) { #ifdef IPSEC_ESP - struct esp_algorithm *algo; + const struct esp_algorithm *algo; int keylen; - switch (sav->alg_enc) { - case SADB_EALG_NONE: - case SADB_EALG_DESCBC: - case SADB_EALG_3DESCBC: - case SADB_EALG_NULL: - case SADB_EALG_BLOWFISHCBC: - case SADB_EALG_CAST128CBC: - case SADB_EALG_RC5CBC: - break; - default: + algo = esp_algorithm_lookup(sav->alg_enc); + if (!algo) { #ifdef IPSEC_DEBUG printf("key_mature: unknown encryption algorithm.\n"); #endif @@ -3122,8 +3327,6 @@ key_mature(sav) } /* algorithm-dependent check */ - algo = &esp_algorithms[sav->alg_enc]; - if (sav->key_enc) keylen = sav->key_enc->sadb_key_bits; else @@ -3161,28 +3364,13 @@ key_mature(sav) /* check compression algorithm */ if ((checkmask & 4) != 0) { - struct ipcomp_algorithm *algo; - - switch (sav->alg_enc) { - case SADB_X_CALG_NONE: - case SADB_X_CALG_OUI: - case SADB_X_CALG_DEFLATE: - case SADB_X_CALG_LZS: - break; - default: -#ifdef IPSEC_DEBUG - printf("key_mature: unknown compression algorithm.\n"); -#endif - return EINVAL; - } + const struct ipcomp_algorithm *algo; /* algorithm-dependent check */ - algo = &ipcomp_algorithms[sav->alg_enc]; - - if (!(algo->compress && algo->decompress)) { + algo = ipcomp_algorithm_lookup(sav->alg_enc); + if (!algo) { #ifdef IPSEC_DEBUG - printf("key_mature: " - "unsupported compression algorithm.\n"); + printf("key_mature: unknown compression algorithm.\n"); #endif return EINVAL; } @@ -3752,7 +3940,50 @@ key_cmpsaidx_withmode(saidx0, saidx1) } /* - * compare two secasindex structure without mode. + * compare two secasindex structure without mode, but think reqid. + * don't compare port. + * IN: + * saidx0: source, it is often in SAD. + * saidx1: object, it is often from user. + * OUT: + * 1 : equal + * 0 : not equal + */ +static int +key_cmpsaidx_withoutmode2(saidx0, saidx1) + struct secasindex *saidx0, *saidx1; +{ + /* sanity */ + if (saidx0 == NULL && saidx1 == NULL) + return 1; + + if (saidx0 == NULL || saidx1 == NULL) + return 0; + + if (saidx0->proto != saidx1->proto) + return 0; + + /* + * If reqid of SPD is non-zero, unique SA is required. + * The result must be of same reqid in this case. + */ + if (saidx1->reqid != 0 && saidx0->reqid != saidx1->reqid) + return 0; + + if (key_sockaddrcmp((struct sockaddr *)&saidx0->src, + (struct sockaddr *)&saidx1->src, 0) != 0) { + return 0; + } + if (key_sockaddrcmp((struct sockaddr *)&saidx0->dst, + (struct sockaddr *)&saidx1->dst, 0) != 0) { + return 0; + } + + return 1; +} + +/* + * compare two secasindex structure without both mode and reqid. * don't compare port. * IN: * saidx0: source, it is often in SAD. @@ -3870,7 +4101,13 @@ key_cmpspidx_withmask(spidx0, spidx1) && satosin6(&spidx0->src)->sin6_port != satosin6(&spidx1->src)->sin6_port) return 0; - if (satosin6(&spidx0->src)->sin6_scope_id != + /* + * scope_id check. if sin6_scope_id is 0, we regard it + * as a wildcard scope, which matches any scope zone ID. + */ + if (satosin6(&spidx0->src)->sin6_scope_id && + satosin6(&spidx1->src)->sin6_scope_id && + satosin6(&spidx0->src)->sin6_scope_id != satosin6(&spidx1->src)->sin6_scope_id) return 0; if (!key_bbcmp((caddr_t)&satosin6(&spidx0->src)->sin6_addr, @@ -3899,7 +4136,13 @@ key_cmpspidx_withmask(spidx0, spidx1) && satosin6(&spidx0->dst)->sin6_port != satosin6(&spidx1->dst)->sin6_port) return 0; - if (satosin6(&spidx0->dst)->sin6_scope_id != + /* + * scope_id check. if sin6_scope_id is 0, we regard it + * as a wildcard scope, which matches any scope zone ID. + */ + if (satosin6(&spidx0->src)->sin6_scope_id && + satosin6(&spidx1->src)->sin6_scope_id && + satosin6(&spidx0->dst)->sin6_scope_id != satosin6(&spidx1->dst)->sin6_scope_id) return 0; if (!key_bbcmp((caddr_t)&satosin6(&spidx0->dst)->sin6_addr, @@ -4005,12 +4248,16 @@ key_bbcmp(p1, p2, bits) * time handler. * scanning SPD and SAD to check status for each entries, * and do to remove or to expire. + * XXX: year 2038 problem may remain. */ void key_timehandler(void) { u_int dir; int s; + struct timeval tv; + + microtime(&tv); s = splnet(); /*called from softclock()*/ @@ -4025,8 +4272,23 @@ key_timehandler(void) nextsp = LIST_NEXT(sp, chain); - if (sp->state == IPSEC_SPSTATE_DEAD) + if (sp->state == IPSEC_SPSTATE_DEAD) { key_freesp(sp); + continue; + } + + if (sp->lifetime == 0 && sp->validtime == 0) + continue; + + /* the deletion will occur next time */ + if ((sp->lifetime + && tv.tv_sec - sp->created > sp->lifetime) + || (sp->validtime + && tv.tv_sec - sp->lastused > sp->validtime)) { + sp->state = IPSEC_SPSTATE_DEAD; + key_spdexpire(sp); + continue; + } } } } @@ -4055,9 +4317,7 @@ key_timehandler(void) nextsav = LIST_NEXT(sav, chain); - sav->tick++; - - if (key_larval_lifetime < sav->tick) { + if (tv.tv_sec - sav->created > key_larval_lifetime) { key_freesav(sav); } } @@ -4072,8 +4332,6 @@ key_timehandler(void) nextsav = LIST_NEXT(sav, chain); - sav->tick++; - /* we don't need to check. */ if (sav->lft_s == NULL) continue; @@ -4087,9 +4345,9 @@ key_timehandler(void) continue; } - /* compare SOFT lifetime and tick */ + /* check SOFT lifetime */ if (sav->lft_s->sadb_lifetime_addtime != 0 - && sav->lft_s->sadb_lifetime_addtime < sav->tick) { + && tv.tv_sec - sav->created > sav->lft_s->sadb_lifetime_addtime) { /* * check SA to be used whether or not. * when SA hasn't been used, delete it. @@ -4134,8 +4392,6 @@ key_timehandler(void) nextsav = LIST_NEXT(sav, chain); - sav->tick++; - /* we don't need to check. */ if (sav->lft_h == NULL) continue; @@ -4149,9 +4405,8 @@ key_timehandler(void) continue; } - /* compare HARD lifetime and tick */ if (sav->lft_h->sadb_lifetime_addtime != 0 - && sav->lft_h->sadb_lifetime_addtime < sav->tick) { + && tv.tv_sec - sav->created > sav->lft_h->sadb_lifetime_addtime) { key_sa_chgstate(sav, SADB_SASTATE_DEAD); key_freesav(sav); sav = NULL; @@ -4159,7 +4414,7 @@ key_timehandler(void) #if 0 /* XXX Should we keep to send expire message until HARD lifetime ? */ else if (sav->lft_s != NULL && sav->lft_s->sadb_lifetime_addtime != 0 - && sav->lft_s->sadb_lifetime_addtime < sav->tick) { + && tv.tv_sec - sav->created > sav->lft_s->sadb_lifetime_addtime) { /* * XXX: should be checked to be * installed the valid SA. @@ -4220,9 +4475,8 @@ key_timehandler(void) nextacq = LIST_NEXT(acq, chain); - acq->tick++; - - if (key_blockacq_lifetime < acq->tick && __LIST_CHAINED(acq)) { + if (tv.tv_sec - acq->created > key_blockacq_lifetime + && __LIST_CHAINED(acq)) { LIST_REMOVE(acq, chain); KFREE(acq); } @@ -4240,9 +4494,8 @@ key_timehandler(void) nextacq = LIST_NEXT(acq, chain); - acq->tick++; - - if (key_blockacq_lifetime < acq->tick && __LIST_CHAINED(acq)) { + if (tv.tv_sec - acq->created > key_blockacq_lifetime + && __LIST_CHAINED(acq)) { LIST_REMOVE(acq, chain); KFREE(acq); } @@ -4257,7 +4510,7 @@ key_timehandler(void) #ifndef IPSEC_DEBUG2 /* do exchange to tick time !! */ - (void)timeout((void *)key_timehandler, (void *)0, 100); + (void)timeout((void *)key_timehandler, (void *)0, hz); #endif /* IPSEC_DEBUG2 */ splx(s); @@ -4279,19 +4532,41 @@ key_srandom() return; } -/* - * to initialize a seed for random() - */ -static u_long +u_long key_random() { u_long value; - value = random(); - + key_randomfill(&value, sizeof(value)); return value; } +void +key_randomfill(p, l) + void *p; + size_t l; +{ + size_t n; + u_long v; + static int warn = 1; + + n = 0; + n = (size_t)read_random(p, (u_int)l); + /* last resort */ + while (n < l) { + v = random(); + bcopy(&v, (u_int8_t *)p + n, + l - n < sizeof(v) ? l - n : sizeof(v)); + n += sizeof(v); + + if (warn) { + printf("WARNING: pseudo-random number generator " + "used for IPsec processing\n"); + warn = 0; + } + } +} + /* * map SADB_SATYPE_* to IPPROTO_*. * if satype == SADB_SATYPE then satype is mapped to ~0. @@ -4309,11 +4584,9 @@ key_satype2proto(satype) return IPPROTO_AH; case SADB_SATYPE_ESP: return IPPROTO_ESP; -#if 1 /*nonstandard*/ case SADB_X_SATYPE_IPCOMP: return IPPROTO_IPCOMP; break; -#endif default: return 0; } @@ -4334,11 +4607,9 @@ key_proto2satype(proto) return SADB_SATYPE_AH; case IPPROTO_ESP: return SADB_SATYPE_ESP; -#if 1 /*nonstandard*/ case IPPROTO_IPCOMP: return SADB_X_SATYPE_IPCOMP; break; -#endif default: return 0; } @@ -4481,8 +4752,10 @@ key_getspi(so, m, mhp) if (mhp->msg->sadb_msg_seq != 0) { struct secacq *acq; if ((acq = key_getacqbyseq(mhp->msg->sadb_msg_seq)) != NULL) { - /* reset counter in order to deletion by timehander. */ - acq->tick = key_blockacq_lifetime; + /* reset counter in order to deletion by timehandler. */ + struct timeval tv; + microtime(&tv); + acq->created = tv.tv_sec; acq->count = 0; } } @@ -5047,6 +5320,7 @@ key_setident(sah, m, mhp) KMALLOC(sah->identd, struct sadb_ident *, iddstlen); if (sah->identd == NULL) { KFREE(sah->idents); + sah->idents = NULL; #ifdef IPSEC_DEBUG printf("key_setident: No more memory.\n"); #endif @@ -5094,6 +5368,9 @@ key_getmsgbuf_x1(m, mhp) return n; } +static int key_delete_all __P((struct socket *, struct mbuf *, + const struct sadb_msghdr *, u_int16_t)); + /* * SADB_DELETE processing * receive @@ -5130,16 +5407,15 @@ key_delete(so, m, mhp) return key_senderror(so, m, EINVAL); } - if (mhp->ext[SADB_EXT_SA] == NULL || - mhp->ext[SADB_EXT_ADDRESS_SRC] == NULL || + if (mhp->ext[SADB_EXT_ADDRESS_SRC] == NULL || mhp->ext[SADB_EXT_ADDRESS_DST] == NULL) { #ifdef IPSEC_DEBUG printf("key_delete: invalid message is passed.\n"); #endif return key_senderror(so, m, EINVAL); } - if (mhp->extlen[SADB_EXT_SA] < sizeof(struct sadb_sa) || - mhp->extlen[SADB_EXT_ADDRESS_SRC] < sizeof(struct sadb_address) || + + if (mhp->extlen[SADB_EXT_ADDRESS_SRC] < sizeof(struct sadb_address) || mhp->extlen[SADB_EXT_ADDRESS_DST] < sizeof(struct sadb_address)) { #ifdef IPSEC_DEBUG printf("key_delete: invalid message is passed.\n"); @@ -5147,6 +5423,23 @@ key_delete(so, m, mhp) return key_senderror(so, m, EINVAL); } + if (mhp->ext[SADB_EXT_SA] == NULL) { + /* + * Caller wants us to delete all non-LARVAL SAs + * that match the src/dst. This is used during + * IKE INITIAL-CONTACT. + */ +#ifdef IPSEC_DEBUG + printf("key_delete: doing delete all.\n"); +#endif + return key_delete_all(so, m, mhp, proto); + } else if (mhp->extlen[SADB_EXT_SA] < sizeof(struct sadb_sa)) { +#ifdef IPSEC_DEBUG + printf("key_delete: invalid message is passed.\n"); +#endif + return key_senderror(so, m, EINVAL); + } + sa0 = (struct sadb_sa *)mhp->ext[SADB_EXT_SA]; src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]); dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]); @@ -5202,6 +5495,84 @@ key_delete(so, m, mhp) } /* + * delete all SAs for src/dst. Called from key_delete(). + */ +static int +key_delete_all(so, m, mhp, proto) + struct socket *so; + struct mbuf *m; + const struct sadb_msghdr *mhp; + u_int16_t proto; +{ + struct sadb_address *src0, *dst0; + struct secasindex saidx; + struct secashead *sah; + struct secasvar *sav, *nextsav; + u_int stateidx, state; + + src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]); + dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]); + + /* XXX boundary check against sa_len */ + KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, &saidx); + + LIST_FOREACH(sah, &sahtree, chain) { + if (sah->state == SADB_SASTATE_DEAD) + continue; + if (key_cmpsaidx_withoutmode(&sah->saidx, &saidx) == 0) + continue; + + /* Delete all non-LARVAL SAs. */ + for (stateidx = 0; + stateidx < _ARRAYLEN(saorder_state_alive); + stateidx++) { + state = saorder_state_alive[stateidx]; + if (state == SADB_SASTATE_LARVAL) + continue; + for (sav = LIST_FIRST(&sah->savtree[state]); + sav != NULL; sav = nextsav) { + nextsav = LIST_NEXT(sav, chain); + /* sanity check */ + if (sav->state != state) { +#ifdef IPSEC_DEBUG + printf("key_delete_all: " + "invalid sav->state " + "(queue: %d SA: %d)\n", + state, sav->state); +#endif + continue; + } + + key_sa_chgstate(sav, SADB_SASTATE_DEAD); + key_freesav(sav); + } + } + } + { + struct mbuf *n; + struct sadb_msg *newmsg; + + /* create new sadb_msg to reply. */ + n = key_gather_mbuf(m, mhp, 1, 3, SADB_EXT_RESERVED, + SADB_EXT_ADDRESS_SRC, SADB_EXT_ADDRESS_DST); + if (!n) + return key_senderror(so, m, ENOBUFS); + + if (n->m_len < sizeof(struct sadb_msg)) { + n = m_pullup(n, sizeof(struct sadb_msg)); + if (n == NULL) + return key_senderror(so, m, ENOBUFS); + } + newmsg = mtod(n, struct sadb_msg *); + newmsg->sadb_msg_errno = 0; + newmsg->sadb_msg_len = PFKEY_UNIT64(n->m_pkthdr.len); + + m_freem(m); + return key_sendup_mbuf(so, n, KEY_SENDUP_ALL); + } +} + +/* * SADB_GET processing * receive * <base, SA(*), address(SD)> @@ -5304,17 +5675,32 @@ key_get(so, m, mhp) } } +/* XXX make it sysctl-configurable? */ +static void +key_getcomb_setlifetime(comb) + struct sadb_comb *comb; +{ + + comb->sadb_comb_soft_allocations = 1; + comb->sadb_comb_hard_allocations = 1; + comb->sadb_comb_soft_bytes = 0; + comb->sadb_comb_hard_bytes = 0; + comb->sadb_comb_hard_addtime = 86400; /* 1 day */ + comb->sadb_comb_soft_addtime = comb->sadb_comb_soft_addtime * 80 / 100; + comb->sadb_comb_soft_usetime = 28800; /* 8 hours */ + comb->sadb_comb_hard_usetime = comb->sadb_comb_hard_usetime * 80 / 100; +} + #ifdef IPSEC_ESP /* * XXX reorder combinations by preference * XXX no idea if the user wants ESP authentication or not - * XXX lifetime - should be in policy? */ static struct mbuf * key_getcomb_esp() { struct sadb_comb *comb; - struct esp_algorithm *algo; + const struct esp_algorithm *algo; struct mbuf *result = NULL, *m, *n; int encmin; int i, off, o; @@ -5322,8 +5708,10 @@ key_getcomb_esp() const int l = PFKEY_ALIGN8(sizeof(struct sadb_comb)); m = NULL; - for (i = 1; i < SADB_EALG_MAX; i++) { - algo = &esp_algorithms[i]; + for (i = 1; i <= SADB_EALG_MAX; i++) { + algo = esp_algorithm_lookup(i); + if (!algo) + continue; if (algo->keymax < ipsec_esp_keymin) continue; @@ -5365,6 +5753,8 @@ key_getcomb_esp() goto fail; } comb = (struct sadb_comb *)(mtod(n, caddr_t) + o); + bzero(comb, sizeof(*comb)); + key_getcomb_setlifetime(comb); comb->sadb_comb_encrypt = i; comb->sadb_comb_encrypt_minbits = encmin; comb->sadb_comb_encrypt_maxbits = algo->keymax; @@ -5387,26 +5777,27 @@ key_getcomb_esp() /* * XXX reorder combinations by preference - * XXX lifetime - should be in policy? */ static struct mbuf * key_getcomb_ah() { struct sadb_comb *comb; - struct ah_algorithm *algo; + const struct ah_algorithm *algo; struct mbuf *m; int min; int i; const int l = PFKEY_ALIGN8(sizeof(struct sadb_comb)); m = NULL; - for (i = 1; i < SADB_AALG_MAX; i++) { + for (i = 1; i <= SADB_AALG_MAX; i++) { #if 1 /* we prefer HMAC algorithms, not old algorithms */ if (i != SADB_AALG_SHA1HMAC && i != SADB_AALG_MD5HMAC) continue; #endif - algo = &ah_algorithms[i]; + algo = ah_algorithm_lookup(i); + if (!algo) + continue; if (algo->keymax < ipsec_ah_keymin) continue; @@ -5433,6 +5824,7 @@ key_getcomb_ah() comb = mtod(m, struct sadb_comb *); bzero(comb, sizeof(*comb)); + key_getcomb_setlifetime(comb); comb->sadb_comb_auth = i; comb->sadb_comb_auth_minbits = min; comb->sadb_comb_auth_maxbits = algo->keymax; @@ -5442,6 +5834,51 @@ key_getcomb_ah() } /* + * not really an official behavior. discussed in pf_key@inner.net in Sep2000. + * XXX reorder combinations by preference + */ +static struct mbuf * +key_getcomb_ipcomp() +{ + struct sadb_comb *comb; + const struct ipcomp_algorithm *algo; + struct mbuf *m; + int i; + const int l = PFKEY_ALIGN8(sizeof(struct sadb_comb)); + + m = NULL; + for (i = 1; i <= SADB_X_CALG_MAX; i++) { + algo = ipcomp_algorithm_lookup(i); + if (!algo) + continue; + + if (!m) { +#ifdef DIAGNOSTIC + if (l > MLEN) + panic("assumption failed in key_getcomb_ipcomp"); +#endif + MGET(m, M_DONTWAIT, MT_DATA); + if (m) { + M_ALIGN(m, l); + m->m_len = l; + m->m_next = NULL; + } + } else + M_PREPEND(m, l, M_DONTWAIT); + if (!m) + return NULL; + + comb = mtod(m, struct sadb_comb *); + bzero(comb, sizeof(*comb)); + key_getcomb_setlifetime(comb); + comb->sadb_comb_encrypt = i; + /* what should we set into sadb_comb_*_{min,max}bits? */ + } + + return m; +} + +/* * XXX no way to pass mode (transport/tunnel) to userland * XXX replay checking? * XXX sysctl interface to ipsec_{ah,esp}_keymin @@ -5464,6 +5901,9 @@ key_getprop(saidx) case IPPROTO_AH: m = key_getcomb_ah(); break; + case IPPROTO_IPCOMP: + m = key_getcomb_ipcomp(); + break; default: return NULL; } @@ -5490,7 +5930,7 @@ key_getprop(saidx) /* * SADB_ACQUIRE processing called by key_checkrequest() and key_acquire2(). * send - * <base, SA, address(SD), (address(P)), + * <base, SA, address(SD), (address(P)), x_policy, * (identity(SD),) (sensitivity,) proposal> * to KMD, and expect to receive * <base> with SADB_ACQUIRE if error occured, @@ -5498,7 +5938,10 @@ key_getprop(saidx) * <base, src address, dst address, (SPI range)> with SADB_GETSPI * from KMD by PF_KEY. * - * sensitivity is not supported. + * XXX x_policy is outside of RFC2367 (KAME extension). + * XXX sensitivity is not supported. + * XXX for ipcomp, RFC2367 does not define how to fill in proposal. + * see comment for key_getcomb_ipcomp(). * * OUT: * 0 : succeed @@ -5639,11 +6082,24 @@ key_acquire(saidx, sp) /* create proposal/combination extension */ m = key_getprop(saidx); +#if 0 + /* + * spec conformant: always attach proposal/combination extension, + * the problem is that we have no way to attach it for ipcomp, + * due to the way sadb_comb is declared in RFC2367. + */ if (!m) { error = ENOBUFS; goto fail; } m_cat(result, m); +#else + /* + * outside of spec; make proposal/combination extension optional. + */ + if (m) + m_cat(result, m); +#endif if ((result->m_flags & M_PKTHDR) == 0) { error = EINVAL; @@ -5679,6 +6135,7 @@ key_newacq(saidx) struct secasindex *saidx; { struct secacq *newacq; + struct timeval tv; /* get new entry */ KMALLOC(newacq, struct secacq *, sizeof(struct secacq)); @@ -5693,7 +6150,8 @@ key_newacq(saidx) /* copy secindex */ bcopy(saidx, &newacq->saidx, sizeof(newacq->saidx)); newacq->seq = (acq_seq == ~0 ? 1 : ++acq_seq); - newacq->tick = 0; + microtime(&tv); + newacq->created = tv.tv_sec; newacq->count = 0; return newacq; @@ -5733,6 +6191,7 @@ key_newspacq(spidx) struct secpolicyindex *spidx; { struct secspacq *acq; + struct timeval tv; /* get new entry */ KMALLOC(acq, struct secspacq *, sizeof(struct secspacq)); @@ -5746,7 +6205,8 @@ key_newspacq(spidx) /* copy secindex */ bcopy(spidx, &acq->spidx, sizeof(acq->spidx)); - acq->tick = 0; + microtime(&tv); + acq->created = tv.tv_sec; acq->count = 0; return acq; @@ -5778,7 +6238,7 @@ key_getspacq(spidx) * <base, address(SD), (address(P),) (identity(SD),) (sensitivity,) proposal> * to the socket. * - * m will always e freed. + * m will always be freed. */ static int key_acquire2(so, m, mhp) @@ -5805,6 +6265,7 @@ key_acquire2(so, m, mhp) if (mhp->msg->sadb_msg_len == PFKEY_UNIT64(sizeof(struct sadb_msg))) { #ifndef IPSEC_NONBLOCK_ACQUIRE struct secacq *acq; + struct timeval tv; /* check sequence number */ if (mhp->msg->sadb_msg_seq == 0) { @@ -5816,16 +6277,17 @@ key_acquire2(so, m, mhp) } if ((acq = key_getacqbyseq(mhp->msg->sadb_msg_seq)) == NULL) { -#ifdef IPSEC_DEBUG - printf("key_acquire2: " - "invalid sequence number is passed.\n"); -#endif + /* + * the specified larval SA is already gone, or we got + * a bogus sequence number. we can silently ignore it. + */ m_freem(m); return 0; } /* reset acq counter in order to deletion by timehander. */ - acq->tick = key_blockacq_lifetime; + microtime(&tv); + acq->created = tv.tv_sec; acq->count = 0; #endif m_freem(m); @@ -5906,7 +6368,7 @@ key_acquire2(so, m, mhp) * to KMD by PF_KEY. * If socket is detached, must free from regnode. * - * m will always e freed. + * m will always be freed. */ static int key_register(so, m, mhp) @@ -5965,13 +6427,21 @@ key_register(so, m, mhp) struct sadb_alg *alg; /* create new sadb_msg to reply. */ - alen = sizeof(struct sadb_supported) - + ((SADB_AALG_MAX - 1) * sizeof(struct sadb_alg)); -#ifdef IPSEC_ESP - elen = sizeof(struct sadb_supported) - + ((SADB_EALG_MAX - 1) * sizeof(struct sadb_alg)); -#else + alen = 0; + for (i = 1; i <= SADB_AALG_MAX; i++) { + if (ah_algorithm_lookup(i)) + alen += sizeof(struct sadb_alg); + } + if (alen) + alen += sizeof(struct sadb_supported); elen = 0; +#ifdef IPSEC_ESP + for (i = 1; i <= SADB_EALG_MAX; i++) { + if (esp_algorithm_lookup(i)) + elen += sizeof(struct sadb_alg); + } + if (elen) + elen += sizeof(struct sadb_supported); #endif len = sizeof(struct sadb_msg) + alen + elen; @@ -6007,10 +6477,12 @@ key_register(so, m, mhp) sup->sadb_supported_exttype = SADB_EXT_SUPPORTED_AUTH; off += PFKEY_ALIGN8(sizeof(*sup)); - for (i = 1; i < SADB_AALG_MAX; i++) { - struct ah_algorithm *aalgo; + for (i = 1; i <= SADB_AALG_MAX; i++) { + const struct ah_algorithm *aalgo; - aalgo = &ah_algorithms[i]; + aalgo = ah_algorithm_lookup(i); + if (!aalgo) + continue; alg = (struct sadb_alg *)(mtod(n, caddr_t) + off); alg->sadb_alg_id = i; alg->sadb_alg_ivlen = 0; @@ -6028,10 +6500,12 @@ key_register(so, m, mhp) sup->sadb_supported_exttype = SADB_EXT_SUPPORTED_ENCRYPT; off += PFKEY_ALIGN8(sizeof(*sup)); - for (i = 1; i < SADB_EALG_MAX; i++) { - struct esp_algorithm *ealgo; + for (i = 1; i <= SADB_EALG_MAX; i++) { + const struct esp_algorithm *ealgo; - ealgo = &esp_algorithms[i]; + ealgo = esp_algorithm_lookup(i); + if (!ealgo) + continue; alg = (struct sadb_alg *)(mtod(n, caddr_t) + off); alg->sadb_alg_id = i; if (ealgo && ealgo->ivlen) { @@ -6039,7 +6513,8 @@ key_register(so, m, mhp) * give NULL to get the value preferred by * algorithm XXX SADB_X_EXT_DERIV ? */ - alg->sadb_alg_ivlen = (*ealgo->ivlen)(NULL); + alg->sadb_alg_ivlen = + (*ealgo->ivlen)(ealgo, NULL); } else alg->sadb_alg_ivlen = 0; alg->sadb_alg_minbits = ealgo->keymin; @@ -6190,13 +6665,17 @@ key_expire(sav) } m_cat(result, m); - if ((result->m_flags & M_PKTHDR) == 0) + if ((result->m_flags & M_PKTHDR) == 0) { + error = EINVAL; goto fail; + } if (result->m_len < sizeof(struct sadb_msg)) { result = m_pullup(result, sizeof(struct sadb_msg)); - if (result == NULL) + if (result == NULL) { + error = ENOBUFS; goto fail; + } } result->m_pkthdr.len = 0; @@ -6608,9 +7087,7 @@ key_parse(m, so) break; case SADB_SATYPE_AH: case SADB_SATYPE_ESP: -#if 1 /*nonstandard*/ case SADB_X_SATYPE_IPCOMP: -#endif switch (msg->sadb_msg_type) { case SADB_X_SPDADD: case SADB_X_SPDDELETE: @@ -6973,8 +7450,10 @@ key_init() LIST_INIT(&spacqtree); /* system default */ +#ifdef INET ip4_def_policy.policy = IPSEC_POLICY_NONE; ip4_def_policy.refcnt++; /*never reclaim this*/ +#endif #ifdef INET6 ip6_def_policy.policy = IPSEC_POLICY_NONE; ip6_def_policy.refcnt++; /*never reclaim this*/ @@ -7167,6 +7646,16 @@ key_sa_chgstate(sav, state) LIST_INSERT_HEAD(&sav->sah->savtree[state], sav, chain); } +void +key_sa_stir_iv(sav) + struct secasvar *sav; +{ + + if (!sav->iv) + panic("key_sa_stir_iv called with sav == NULL"); + key_randomfill(sav->iv, sav->ivlen); +} + /* XXX too much? */ static struct mbuf * key_alloc_mbuf(l) diff --git a/sys/netkey/key.h b/sys/netkey/key.h index 65a2755..20bcaa0 100644 --- a/sys/netkey/key.h +++ b/sys/netkey/key.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: key.h,v 1.17 2000/06/12 07:01:13 itojun Exp $ */ +/* $KAME: key.h,v 1.20 2001/03/22 08:09:32 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -47,6 +47,8 @@ struct sadb_msg; struct sadb_x_policy; extern struct secpolicy *key_allocsp __P((struct secpolicyindex *, u_int)); +extern struct secpolicy *key_gettunnel __P((struct sockaddr *, + struct sockaddr *, struct sockaddr *, struct sockaddr *)); extern int key_checkrequest __P((struct ipsecrequest *isr, struct secasindex *)); extern struct secasvar *key_allocsa __P((u_int, caddr_t, caddr_t, @@ -61,6 +63,8 @@ extern struct mbuf *key_sp2msg __P((struct secpolicy *)); extern int key_ismyaddr __P((struct sockaddr *)); extern int key_spdacquire __P((struct secpolicy *)); extern void key_timehandler __P((void)); +extern u_long key_random __P((void)); +extern void key_randomfill __P((void *, size_t)); extern void key_freereg __P((struct socket *)); extern int key_parse __P((struct mbuf *, struct socket *)); extern void key_init __P((void)); @@ -68,6 +72,7 @@ extern int key_checktunnelsanity __P((struct secasvar *, u_int, caddr_t, caddr_t)); extern void key_sa_recordxfer __P((struct secasvar *, struct mbuf *)); extern void key_sa_routechange __P((struct sockaddr *)); +extern void key_sa_stir_iv __P((struct secasvar *)); #ifdef MALLOC_DECLARE MALLOC_DECLARE(M_SECA); diff --git a/sys/netkey/key_debug.c b/sys/netkey/key_debug.c index 3e8b12b..76a59f3 100644 --- a/sys/netkey/key_debug.c +++ b/sys/netkey/key_debug.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: key_debug.c,v 1.23 2000/07/04 04:08:15 itojun Exp $ */ +/* $KAME: key_debug.c,v 1.25 2000/07/24 13:23:12 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -41,17 +41,14 @@ #ifdef _KERNEL #include <sys/systm.h> #include <sys/mbuf.h> +#include <sys/queue.h> #endif #include <sys/socket.h> #include <net/route.h> #include <netkey/key_var.h> -#ifdef IPSEC_DEBUG #include <netkey/key_debug.h> -#else -#define KEYDEBUG(lev,arg) -#endif #include <netinet/in.h> #include <netinet6/ipsec.h> diff --git a/sys/netkey/key_debug.h b/sys/netkey/key_debug.h index 383a0e8..f75a535 100644 --- a/sys/netkey/key_debug.h +++ b/sys/netkey/key_debug.h @@ -33,6 +33,8 @@ #ifndef _NETKEY_KEY_DEBUG_H_ #define _NETKEY_KEY_DEBUG_H_ +#if !defined(_KERNEL) || (defined(_KERNEL) && defined(IPSEC_DEBUG)) + /* debug flags */ #define KEYDEBUG_STAMP 0x00000001 /* path */ #define KEYDEBUG_DATA 0x00000002 /* data */ @@ -84,5 +86,10 @@ extern void kdebug_sockaddr __P((struct sockaddr *)); extern void ipsec_hexdump __P((caddr_t, int)); extern void ipsec_bindump __P((caddr_t, int)); -#endif /* _NETKEY_KEY_DEBUG_H_ */ +#else + +#define KEYDEBUG(lev,arg) +#endif /*!defined(_KERNEL) || (defined(_KERNEL) && defined(IPSEC_DEBUG))*/ + +#endif /* _NETKEY_KEY_DEBUG_H_ */ diff --git a/sys/netkey/key_var.h b/sys/netkey/key_var.h index b7a62ba..4043a03 100644 --- a/sys/netkey/key_var.h +++ b/sys/netkey/key_var.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: key_var.h,v 1.8 2000/05/24 17:28:23 itojun Exp $ */ +/* $KAME: key_var.h,v 1.9 2000/10/04 11:13:57 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -42,7 +42,10 @@ #define KEYCTL_LARVAL_LIFETIME 6 #define KEYCTL_BLOCKACQ_COUNT 7 #define KEYCTL_BLOCKACQ_LIFETIME 8 -#define KEYCTL_MAXID 9 +#define KEYCTL_ESP_KEYMIN 9 +#define KEYCTL_ESP_AUTH 10 +#define KEYCTL_AH_KEYMIN 11 +#define KEYCTL_MAXID 12 #define KEYCTL_NAMES { \ { 0, 0 }, \ @@ -54,8 +57,40 @@ { "larval_lifetime", CTLTYPE_INT }, \ { "blockacq_count", CTLTYPE_INT }, \ { "blockacq_lifetime", CTLTYPE_INT }, \ + { "esp_keymin", CTLTYPE_INT }, \ + { "ah_keymin", CTLTYPE_INT }, \ } +#ifdef IPSEC_DEBUG +#define KEYCTL_VARS { \ + 0, \ + &key_debug_level, \ + &key_spi_trycnt, \ + &key_spi_minval, \ + &key_spi_maxval, \ + &key_int_random, \ + &key_larval_lifetime, \ + &key_blockacq_count, \ + &key_blockacq_lifetime, \ + &ipsec_esp_keymin, \ + &ipsec_ah_keymin, \ +} +#else +#define KEYCTL_VARS { \ + 0, \ + 0, \ + &key_spi_trycnt, \ + &key_spi_minval, \ + &key_spi_maxval, \ + &key_int_random, \ + &key_larval_lifetime, \ + &key_blockacq_count, \ + &key_blockacq_lifetime, \ + &ipsec_esp_keymin, \ + &ipsec_ah_keymin, \ +} +#endif + #ifdef _KERNEL #define _ARRAYLEN(p) (sizeof(p)/sizeof(p[0])) #define _KEYLEN(key) ((u_int)((key)->sadb_key_bits >> 3)) diff --git a/sys/netkey/keydb.h b/sys/netkey/keydb.h index fcb478c..1aff5be 100644 --- a/sys/netkey/keydb.h +++ b/sys/netkey/keydb.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: keydb.h,v 1.11 2000/06/15 12:20:50 sakane Exp $ */ +/* $KAME: keydb.h,v 1.14 2000/08/02 17:58:26 sakane Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -82,14 +82,11 @@ struct secasvar { struct sadb_key *key_enc; /* Key for Encryption */ caddr_t iv; /* Initilization Vector */ u_int ivlen; /* length of IV */ -#if 0 - caddr_t misc1; - caddr_t misc2; - caddr_t misc3; -#endif + void *sched; /* intermediate encryption key */ + size_t schedlen; struct secreplay *replay; /* replay prevention */ - u_int32_t tick; /* for lifetime */ + long created; /* for lifetime */ struct sadb_lifetime *lft_c; /* CURRENT lifetime, it's constant. */ struct sadb_lifetime *lft_h; /* HARD lifetime */ @@ -126,7 +123,7 @@ struct secacq { struct secasindex saidx; u_int32_t seq; /* sequence number */ - u_int32_t tick; /* for lifetime */ + long created; /* for lifetime */ int count; /* for lifetime */ }; #endif diff --git a/sys/netkey/keysock.c b/sys/netkey/keysock.c index 68c70c8..5eab147 100644 --- a/sys/netkey/keysock.c +++ b/sys/netkey/keysock.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: keysock.c,v 1.22 2000/05/23 13:19:21 itojun Exp $ */ +/* $KAME: keysock.c,v 1.24 2000/12/03 00:41:48 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -56,11 +56,7 @@ #include <netkey/keydb.h> #include <netkey/key.h> #include <netkey/keysock.h> -#ifdef IPSEC_DEBUG #include <netkey/key_debug.h> -#else -#define KEYDEBUG(lev,arg) -#endif #include <machine/stdarg.h> @@ -158,6 +154,8 @@ key_sendup0(rp, m, promisc) struct mbuf *m; int promisc; { + int error; + if (promisc) { struct sadb_msg *pmsg; @@ -184,17 +182,18 @@ key_sendup0(rp, m, promisc) pfkeystat.in_msgtype[pmsg->sadb_msg_type]++; } - if (!sbappendaddr(&rp->rcb_socket->so_rcv, - (struct sockaddr *)&key_src, m, NULL)) { + if (!sbappendaddr(&rp->rcb_socket->so_rcv, (struct sockaddr *)&key_src, + m, NULL)) { #ifdef IPSEC_DEBUG printf("key_sendup0: sbappendaddr failed\n"); #endif pfkeystat.in_nomem++; m_freem(m); - return ENOBUFS; - } + error = ENOBUFS; + } else + error = 0; sorwakeup(rp->rcb_socket); - return 0; + return error; } /* XXX this interface should be obsoleted. */ |