- /* initialization */
- for (int i = 0; i < MAX_REPLAY_WINDOWS; i++) {
- sav->replay[i] = 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;
- sav->remote_ike_port = 0;
- sav->natt_last_activity = natt_now;
- sav->natt_encapsulated_src_port = 0;
-
- sav->alg_auth = alg_auth;
- sav->alg_enc = alg_enc;
- sav->flags = flags;
- sav->pid = pid;
- sav->seq = seq;
- key_setspi(sav, htonl(spi));
-
- /*
- * Verify that a nat-traversal port was specified if
- * the nat-traversal flag is set.
- */
- if ((sav->flags & SADB_X_EXT_NATT) != 0) {
- if (natt_port == 0) {
- ipseclog((LOG_DEBUG, "key_setsaval2: natt port not set.\n"));
- error = EINVAL;
- goto fail;
- }
- sav->remote_ike_port = natt_port;
- }
-
- /*
- * 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) {
- if ((sav->flags2 & SADB_X_EXT_SA2_SEQ_PER_TRAFFIC_CLASS) ==
- SADB_X_EXT_SA2_SEQ_PER_TRAFFIC_CLASS) {
- uint32_t range = (1ULL << (sizeof(((struct secreplay *)0)->count) * 8)) / MAX_REPLAY_WINDOWS;
- for (int i = 0; i < MAX_REPLAY_WINDOWS; i++) {
- sav->replay[i] = keydb_newsecreplay(replay);
- if (sav->replay[i] == NULL) {
- ipseclog((LOG_DEBUG, "key_setsaval: No more memory.\n"));
- error = ENOBUFS;
- goto fail;
- }
- /* Allowed range for sequence per traffic class */
- sav->replay[i]->count = i * range;
- sav->replay[i]->lastseq = ((i + 1) * range) - 1;
- }
- } else {
- sav->replay[0] = keydb_newsecreplay(replay);
- if (sav->replay[0] == NULL) {
- ipseclog((LOG_DEBUG, "key_setsaval: No more memory.\n"));
- error = ENOBUFS;
- goto fail;
- }
- sav->replay[0]->lastseq = ~0;
- }
- }
-
- /* 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 */
- if (sav->alg_enc == SADB_X_EALG_AES_GCM) {
- bzero(sav->iv, sav->ivlen);
- } else {
- 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 */
- for (int i = 0; i < MAX_REPLAY_WINDOWS; i++) {
- if (sav->replay[i] != NULL) {
- keydb_delsecreplay(sav->replay[i]);
- sav->replay[i] = 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: