+ /*
+ * Verify if SADB_X_EXT_NATT_MULTIPLEUSERS flag is set that
+ * SADB_X_EXT_NATT is set and SADB_X_EXT_NATT_KEEPALIVE is not
+ * set (we're not behind nat) - otherwise clear it.
+ */
+ if ((sav->flags & SADB_X_EXT_NATT_MULTIPLEUSERS) != 0)
+ if ((sav->flags & SADB_X_EXT_NATT) == 0 ||
+ (sav->flags & SADB_X_EXT_NATT_KEEPALIVE) != 0)
+ sav->flags &= ~SADB_X_EXT_NATT_MULTIPLEUSERS;
+
+ /* replay window */
+ if ((flags & SADB_X_EXT_OLD) == 0) {
+ sav->replay = keydb_newsecreplay(replay);
+ if (sav->replay == NULL) {
+ ipseclog((LOG_DEBUG, "key_setsaval: No more memory.\n"));
+ error = ENOBUFS;
+ goto fail;
+ }
+ }
+
+ /* Authentication keys */
+ sav->key_auth = (__typeof__(sav->key_auth))key_newbuf(key_auth, key_auth_len);
+ if (sav->key_auth == NULL) {
+ ipseclog((LOG_DEBUG, "key_setsaval: No more memory.\n"));
+ error = ENOBUFS;
+ goto fail;
+ }
+
+ /* Encryption key */
+ sav->key_enc = (__typeof__(sav->key_enc))key_newbuf(key_enc, key_enc_len);
+ if (sav->key_enc == NULL) {
+ ipseclog((LOG_DEBUG, "key_setsaval: No more memory.\n"));
+ error = ENOBUFS;
+ goto fail;
+ }
+
+ /* set iv */
+ sav->ivlen = 0;
+
+ if (satype == SADB_SATYPE_ESP) {
+#if IPSEC_ESP
+ algo = esp_algorithm_lookup(sav->alg_enc);
+ if (algo && algo->ivlen)
+ sav->ivlen = (*algo->ivlen)(algo, sav);
+ if (sav->ivlen != 0) {
+ KMALLOC_NOWAIT(sav->iv, caddr_t, sav->ivlen);
+ if (sav->iv == 0) {
+ lck_mtx_unlock(sadb_mutex);
+ KMALLOC_WAIT(sav->iv, caddr_t, sav->ivlen);
+ lck_mtx_lock(sadb_mutex);
+ if (sav->iv == 0) {
+ ipseclog((LOG_DEBUG, "key_setsaval: No more memory.\n"));
+ error = ENOBUFS;
+ goto fail;
+ }
+ }
+ /* initialize */
+ key_randomfill(sav->iv, sav->ivlen);
+ }
+#endif
+ }
+
+ /* reset created */
+ microtime(&tv);
+ sav->created = tv.tv_sec;
+
+ /* make lifetime for CURRENT */
+ KMALLOC_NOWAIT(sav->lft_c, struct sadb_lifetime *,
+ sizeof(struct sadb_lifetime));
+ if (sav->lft_c == NULL) {
+ lck_mtx_unlock(sadb_mutex);
+ KMALLOC_WAIT(sav->lft_c, struct sadb_lifetime *,
+ sizeof(struct sadb_lifetime));
+ lck_mtx_lock(sadb_mutex);
+ if (sav->lft_c == NULL) {
+ ipseclog((LOG_DEBUG, "key_setsaval: No more memory.\n"));
+ error = ENOBUFS;
+ goto fail;
+ }
+ }
+
+ microtime(&tv);
+
+ sav->lft_c->sadb_lifetime_len =
+ PFKEY_UNIT64(sizeof(struct sadb_lifetime));
+ sav->lft_c->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT;
+ sav->lft_c->sadb_lifetime_allocations = 0;
+ sav->lft_c->sadb_lifetime_bytes = 0;
+ sav->lft_c->sadb_lifetime_addtime = tv.tv_sec;
+ sav->lft_c->sadb_lifetime_usetime = 0;
+
+ /* lifetimes for HARD and SOFT */
+ sav->lft_h = (__typeof__(sav->lft_h))key_newbuf(lifetime_hard,
+ sizeof(*lifetime_hard));
+ if (sav->lft_h == NULL) {
+ ipseclog((LOG_DEBUG, "key_setsaval: No more memory.\n"));
+ error = ENOBUFS;
+ goto fail;
+ }
+ sav->lft_s = (__typeof__(sav->lft_s))key_newbuf(lifetime_soft,
+ sizeof(*lifetime_soft));
+ if (sav->lft_s == NULL) {
+ ipseclog((LOG_DEBUG, "key_setsaval: No more memory.\n"));
+ error = ENOBUFS;
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ /* initialization */
+ if (sav->replay != NULL) {
+ keydb_delsecreplay(sav->replay);
+ sav->replay = NULL;
+ }
+ if (sav->key_auth != NULL) {
+ bzero(_KEYBUF(sav->key_auth), _KEYLEN(sav->key_auth));
+ KFREE(sav->key_auth);
+ sav->key_auth = NULL;
+ }
+ if (sav->key_enc != NULL) {
+ bzero(_KEYBUF(sav->key_enc), _KEYLEN(sav->key_enc));
+ KFREE(sav->key_enc);
+ sav->key_enc = NULL;
+ }
+ if (sav->sched) {
+ bzero(sav->sched, sav->schedlen);
+ KFREE(sav->sched);
+ sav->sched = NULL;
+ }
+ if (sav->iv != NULL) {
+ KFREE(sav->iv);
+ sav->iv = NULL;
+ }
+ if (sav->lft_c != NULL) {
+ KFREE(sav->lft_c);
+ sav->lft_c = NULL;
+ }
+ if (sav->lft_h != NULL) {
+ KFREE(sav->lft_h);
+ sav->lft_h = NULL;
+ }
+ if (sav->lft_s != NULL) {
+ KFREE(sav->lft_s);
+ sav->lft_s = NULL;
+ }
+
+ return error;
+}
+
+/*
+ * validation with a secasvar entry, and set SADB_SATYPE_MATURE.
+ * OUT: 0: valid
+ * other: errno
+ */
+static int
+key_mature(
+ struct secasvar *sav)
+{
+ int mature;
+ int checkmask = 0; /* 2^0: ealg 2^1: aalg 2^2: calg */
+ int mustmask = 0; /* 2^0: ealg 2^1: aalg 2^2: calg */
+
+ mature = 0;
+
+ lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+
+ /* check SPI value */
+ switch (sav->sah->saidx.proto) {
+ case IPPROTO_ESP:
+ case IPPROTO_AH:
+
+ /* No reason to test if this is >= 0, because ntohl(sav->spi) is unsigned. */
+ if (ntohl(sav->spi) <= 255) {
+ ipseclog((LOG_DEBUG,
+ "key_mature: illegal range of SPI %u.\n",
+ (u_int32_t)ntohl(sav->spi)));
+ return EINVAL;
+ }
+ break;
+ }
+
+ /* check satype */
+ switch (sav->sah->saidx.proto) {
+ case IPPROTO_ESP:
+ /* check flags */
+ if ((sav->flags & SADB_X_EXT_OLD)
+ && (sav->flags & SADB_X_EXT_DERIV)) {
+ ipseclog((LOG_DEBUG, "key_mature: "
+ "invalid flag (derived) given to old-esp.\n"));
+ return EINVAL;
+ }
+ if (sav->alg_auth == SADB_AALG_NONE)
+ checkmask = 1;
+ else
+ checkmask = 3;
+ mustmask = 1;
+ break;
+ case IPPROTO_AH:
+ /* check flags */
+ if (sav->flags & SADB_X_EXT_DERIV) {
+ ipseclog((LOG_DEBUG, "key_mature: "
+ "invalid flag (derived) given to AH SA.\n"));
+ return EINVAL;
+ }
+ if (sav->alg_enc != SADB_EALG_NONE) {
+ ipseclog((LOG_DEBUG, "key_mature: "
+ "protocol and algorithm mismated.\n"));
+ return(EINVAL);