]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/netinet6/esp_chachapoly.c
xnu-4903.221.2.tar.gz
[apple/xnu.git] / bsd / netinet6 / esp_chachapoly.c
index 0970f698319e1b26e7aaf84dca73ef7ebcc68179..2c68e6f078ca97c577274efe6817691041cfe8e1 100644 (file)
@@ -79,11 +79,12 @@ typedef struct _esp_chachapoly_ctx {
                }                                                                                                                                               \
        } while (0)
 
-#define ESP_CHECK_ARG(_arg) ESP_ASSERT(_arg != NULL, #_arg "is NULL")
+#define ESP_CHECK_ARG(_arg) ESP_ASSERT(_arg != NULL, #_arg " is NULL")
 
 #define _esp_log(_level, _format, ...)  \
        log(_level, "%s:%d " _format, __FUNCTION__, __LINE__, ##__VA_ARGS__)
 #define esp_log_err(_format, ...) _esp_log(LOG_ERR, _format, ##__VA_ARGS__)
+#define esp_log_default(_format, ...) _esp_log(LOG_NOTICE, _format, ##__VA_ARGS__)
 
 #define _esp_packet_log(_level, _format, ...)  \
        ipseclog((_level, "%s:%d " _format, __FUNCTION__, __LINE__, ##__VA_ARGS__))
@@ -97,38 +98,47 @@ esp_chachapoly_mature(struct secasvar *sav)
        ESP_CHECK_ARG(sav);
 
        if ((sav->flags & SADB_X_EXT_OLD) != 0) {
-               esp_log_err("ChaChaPoly is incompatible with SADB_X_EXT_OLD");
+               esp_log_err("ChaChaPoly is incompatible with SADB_X_EXT_OLD, SPI 0x%08x",
+                                       ntohl(sav->spi));
                return 1;
        }
        if ((sav->flags & SADB_X_EXT_DERIV) != 0) {
-               esp_log_err("ChaChaPoly is incompatible with SADB_X_EXT_DERIV");
+               esp_log_err("ChaChaPoly is incompatible with SADB_X_EXT_DERIV, SPI 0x%08x",
+                                       ntohl(sav->spi));
                return 1;
        }
 
        if (sav->alg_enc != SADB_X_EALG_CHACHA20POLY1305) {
-               esp_log_err("ChaChaPoly unsupported algorithm %d",
-                                       sav->alg_enc);
+               esp_log_err("ChaChaPoly unsupported algorithm %d, SPI 0x%08x",
+                                       sav->alg_enc, ntohl(sav->spi));
                return 1;
        }
 
        if (sav->key_enc == NULL) {
-               esp_log_err("ChaChaPoly key is missing");
+               esp_log_err("ChaChaPoly key is missing, SPI 0x%08x",
+                                       ntohl(sav->spi));
                return 1;
        }
 
        algo = esp_algorithm_lookup(sav->alg_enc);
        if (algo == NULL) {
-               esp_log_err("ChaChaPoly lookup failed for algorithm %d",
-                                       sav->alg_enc);
+               esp_log_err("ChaChaPoly lookup failed for algorithm %d, SPI 0x%08x",
+                                       sav->alg_enc, ntohl(sav->spi));
                return 1;
        }
 
        if (sav->key_enc->sadb_key_bits != ESP_CHACHAPOLY_KEYBITS_WITH_SALT) {
-               esp_log_err("ChaChaPoly invalid key length %d bits",
-                                       sav->key_enc->sadb_key_bits);
+               esp_log_err("ChaChaPoly invalid key length %d bits, SPI 0x%08x",
+                                       sav->key_enc->sadb_key_bits, ntohl(sav->spi));
                return 1;
        }
 
+       esp_log_default("ChaChaPoly Mature SPI 0x%08x%s %s dir %u state %u mode %u",
+                                       ntohl(sav->spi),
+                                       (((sav->flags & SADB_X_EXT_IIV) != 0) ? " IIV" : ""),
+                                       ((sav->sah->ipsec_if != NULL) ? if_name(sav->sah->ipsec_if) : "NONE"),
+                                       sav->sah->dir, sav->sah->state, sav->sah->saidx.mode);
+
        return 0;
 }
 
@@ -146,22 +156,27 @@ esp_chachapoly_schedule(__unused const struct esp_algorithm *algo,
        int rc = 0;
 
        ESP_CHECK_ARG(sav);
-       if (sav->ivlen != ESP_CHACHAPOLY_IV_LEN) {
-               esp_log_err("Invalid ivlen %u", sav->ivlen);
-               return EINVAL;
-       }
        if (_KEYLEN(sav->key_enc) != ESP_CHACHAPOLY_KEY_LEN + ESP_CHACHAPOLY_SALT_LEN) {
-               esp_log_err("Invalid key len %u", _KEYLEN(sav->key_enc));
+               esp_log_err("ChaChaPoly Invalid key len %u, SPI 0x%08x",
+                                       _KEYLEN(sav->key_enc), ntohl(sav->spi));
                return EINVAL;
        }
        LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
 
        esp_ccp_ctx = (esp_chachapoly_ctx_t)sav->sched;
+       esp_ccp_ctx->ccp_implicit_iv = ((sav->flags & SADB_X_EXT_IIV) != 0);
+
+       if (sav->ivlen != (esp_ccp_ctx->ccp_implicit_iv ? 0 : ESP_CHACHAPOLY_IV_LEN)) {
+               esp_log_err("ChaChaPoly Invalid ivlen %u, SPI 0x%08x",
+                                       sav->ivlen, ntohl(sav->spi));
+               return EINVAL;
+       }
 
        rc = chacha20poly1305_init(&esp_ccp_ctx->ccp_ctx,
                                                           (const uint8_t *)_KEYBUF(sav->key_enc));
        if (rc != 0) {
-               esp_log_err("chacha20poly1305_init returned %d", rc);
+               esp_log_err("ChaChaPoly chacha20poly1305_init failed %d, SPI 0x%08x",
+                                       rc, ntohl(sav->spi));
                return rc;
        }
 
@@ -169,11 +184,30 @@ esp_chachapoly_schedule(__unused const struct esp_algorithm *algo,
                   (const uint8_t *)_KEYBUF(sav->key_enc) + ESP_CHACHAPOLY_KEY_LEN,
                   sizeof(esp_ccp_ctx->ccp_salt));
 
-       esp_ccp_ctx->ccp_implicit_iv = ((sav->flags & SADB_X_EXT_IIV) != 0);
+
+       esp_log_default("ChaChaPoly Schedule SPI 0x%08x%s %s dir %u state %u mode %u",
+                                       ntohl(sav->spi), (esp_ccp_ctx->ccp_implicit_iv ? " IIV" : ""),
+                                       ((sav->sah->ipsec_if != NULL) ? if_name(sav->sah->ipsec_if) : "NONE"),
+                                       sav->sah->dir, sav->sah->state, sav->sah->saidx.mode);
 
        return 0;
 }
 
+int
+esp_chachapoly_ivlen(const struct esp_algorithm *algo,
+                                        struct secasvar *sav)
+{
+       ESP_CHECK_ARG(algo);
+
+       if (sav != NULL &&
+               ((sav->sched != NULL && ((esp_chachapoly_ctx_t)sav->sched)->ccp_implicit_iv) ||
+                ((sav->flags & SADB_X_EXT_IIV) != 0))) {
+               return 0;
+       } else {
+               return algo->ivlenval;
+       }
+}
+
 int
 esp_chachapoly_encrypt_finalize(struct secasvar *sav,
                                                                unsigned char *tag,
@@ -185,14 +219,16 @@ esp_chachapoly_encrypt_finalize(struct secasvar *sav,
        ESP_CHECK_ARG(sav);
        ESP_CHECK_ARG(tag);
        if (tag_bytes != ESP_CHACHAPOLY_ICV_LEN) {
-               esp_log_err("Invalid tag_bytes %u", tag_bytes);
+               esp_log_err("ChaChaPoly Invalid tag_bytes %u, SPI 0x%08x",
+                                       tag_bytes, ntohl(sav->spi));
                return EINVAL;
        }
 
        esp_ccp_ctx = (esp_chachapoly_ctx_t)sav->sched;
        rc = chacha20poly1305_finalize(&esp_ccp_ctx->ccp_ctx, tag);
        if (rc != 0) {
-               esp_log_err("chacha20poly1305_finalize returned %d", rc);
+               esp_log_err("ChaChaPoly chacha20poly1305_finalize failed %d, SPI 0x%08x",
+                                       rc, ntohl(sav->spi));
                return rc;
        }
        return 0;
@@ -209,14 +245,16 @@ esp_chachapoly_decrypt_finalize(struct secasvar *sav,
        ESP_CHECK_ARG(sav);
        ESP_CHECK_ARG(tag);
        if (tag_bytes != ESP_CHACHAPOLY_ICV_LEN) {
-               esp_log_err("Invalid tag_bytes %u", tag_bytes);
+               esp_log_err("ChaChaPoly Invalid tag_bytes %u, SPI 0x%08x",
+                                       tag_bytes, ntohl(sav->spi));
                return EINVAL;
        }
 
        esp_ccp_ctx = (esp_chachapoly_ctx_t)sav->sched;
        rc = chacha20poly1305_verify(&esp_ccp_ctx->ccp_ctx, tag);
        if (rc != 0) {
-               esp_log_err("chacha20poly1305_finalize returned %d", rc);
+               esp_packet_log_err("ChaChaPoly chacha20poly1305_verify failed %d, SPI 0x%08x",
+                                                  rc, ntohl(sav->spi));
                return rc;
        }
        return 0;
@@ -236,35 +274,36 @@ esp_chachapoly_encrypt(struct mbuf *m, // head of mbuf chain
        uint8_t *sp; // buffer of a given encryption round
        size_t len; // length of a given encryption round
        const int32_t ivoff = (int32_t)off + (int32_t)sizeof(struct newesp); // IV offset
-       int32_t bodyoff; // body offset
+       const int32_t bodyoff = ivoff + ivlen; // body offset
        int rc = 0; // return code of corecrypto operations
        struct newesp esp_hdr; // ESP header for AAD
        _Static_assert(sizeof(esp_hdr) == 8, "Bad size");
-       uint8_t nonce[ESP_CHACHAPOLY_NONCE_LEN];
+       uint32_t nonce[ESP_CHACHAPOLY_NONCE_LEN / 4]; // ensure 32bit alignment
+       _Static_assert(sizeof(nonce) == ESP_CHACHAPOLY_NONCE_LEN, "Bad nonce length");
        esp_chachapoly_ctx_t esp_ccp_ctx;
 
        ESP_CHECK_ARG(m);
        ESP_CHECK_ARG(sav);
-       if (ivlen != ESP_CHACHAPOLY_IV_LEN) {
+
+       esp_ccp_ctx = (esp_chachapoly_ctx_t)sav->sched;
+
+       if (ivlen != (esp_ccp_ctx->ccp_implicit_iv ? 0 : ESP_CHACHAPOLY_IV_LEN)) {
                m_freem(m);
-               esp_log_err("Invalid ivlen %u", ivlen);
+               esp_log_err("ChaChaPoly Invalid ivlen %u, SPI 0x%08x",
+                                       ivlen, ntohl(sav->spi));
                return EINVAL;
        }
-       if (sav->ivlen != ESP_CHACHAPOLY_IV_LEN) {
+       if (sav->ivlen != ivlen) {
                m_freem(m);
-               esp_log_err("Invalid sav->ivlen %u", sav->ivlen);
+               esp_log_err("ChaChaPoly Invalid sav->ivlen %u, SPI 0x%08x",
+                                       sav->ivlen, ntohl(sav->spi));
                return EINVAL;
        }
 
-       esp_ccp_ctx = (esp_chachapoly_ctx_t)sav->sched;
-       if (esp_ccp_ctx->ccp_implicit_iv) {
-               bodyoff = ivoff;
-       } else {
-               bodyoff = ivoff + ivlen;
-       }
        // check if total packet length is enough to contain ESP + IV
        if (m->m_pkthdr.len < bodyoff) {
-               esp_log_err("Packet too short %d < %zu", m->m_pkthdr.len, bodyoff);
+               esp_log_err("ChaChaPoly Packet too short %d < %zu, SPI 0x%08x",
+                                       m->m_pkthdr.len, bodyoff, ntohl(sav->spi));
                m_freem(m);
                return EINVAL;
        }
@@ -272,45 +311,52 @@ esp_chachapoly_encrypt(struct mbuf *m, // head of mbuf chain
        rc = chacha20poly1305_reset(&esp_ccp_ctx->ccp_ctx);
        if (rc != 0) {
                m_freem(m);
-               esp_log_err("chacha20poly1305_reset failed %d", rc);
+               esp_log_err("ChaChaPoly chacha20poly1305_reset failed %d, SPI 0x%08x",
+                                       rc, ntohl(sav->spi));
                return rc;
        }
 
+       // esp_hdr is used for nonce and AAD
+       m_copydata(m, (int)off, sizeof(esp_hdr), (void *)&esp_hdr);
+
        // RFC 7634 dictates that the 12 byte nonce must be
        // the 4 byte salt followed by the 8 byte IV.
        // The IV MUST be non-repeating but does not need to be unpredictable,
        // so we use 4 bytes of 0 followed by the 4 byte ESP sequence number.
-       // this allows us to use implicit IV -- draft-mglt-ipsecme-implicit-iv
-       memset(sav->iv, 0, 4);
-       memcpy(sav->iv + 4, &sav->seq, sizeof(sav->seq));
-       _Static_assert(4 + sizeof(sav->seq) == ESP_CHACHAPOLY_IV_LEN,
-                                  "Bad IV length");
+       // this allows us to use implicit IV -- draft-ietf-ipsecme-implicit-iv
+       // Note that sav->seq is zero here so we must get esp_seq from esp_hdr
        memcpy(nonce, esp_ccp_ctx->ccp_salt, ESP_CHACHAPOLY_SALT_LEN);
-       memcpy(nonce + ESP_CHACHAPOLY_SALT_LEN, sav->iv, ESP_CHACHAPOLY_IV_LEN);
+       memset(((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN, 0, 4);
+       memcpy(((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN + 4,
+                  &esp_hdr.esp_seq, sizeof(esp_hdr.esp_seq));
+
+       _Static_assert(4 + sizeof(esp_hdr.esp_seq) == ESP_CHACHAPOLY_IV_LEN,
+                                  "Bad IV length");
        _Static_assert(ESP_CHACHAPOLY_SALT_LEN + ESP_CHACHAPOLY_IV_LEN == sizeof(nonce),
                                   "Bad nonce length");
 
-       rc = chacha20poly1305_setnonce(&esp_ccp_ctx->ccp_ctx, nonce);
+       rc = chacha20poly1305_setnonce(&esp_ccp_ctx->ccp_ctx, (uint8_t *)nonce);
        if (rc != 0) {
                m_freem(m);
-               esp_log_err("chacha20poly1305_setnonce failed %d", rc);
+               esp_log_err("ChaChaPoly chacha20poly1305_setnonce failed %d, SPI 0x%08x",
+                                       rc, ntohl(sav->spi));
                return rc;
        }
 
        if (!esp_ccp_ctx->ccp_implicit_iv) {
+               memcpy(sav->iv, ((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN, ESP_CHACHAPOLY_IV_LEN);
                m_copyback(m, ivoff, ivlen, sav->iv);
        }
        cc_clear(sizeof(nonce), nonce);
 
        // Set Additional Authentication Data (AAD)
-       m_copydata(m, (int)off, sizeof(esp_hdr), (void *)&esp_hdr);
-
        rc = chacha20poly1305_aad(&esp_ccp_ctx->ccp_ctx,
                                                          sizeof(esp_hdr),
                                                          (void *)&esp_hdr);
        if (rc != 0) {
                m_freem(m);
-               esp_log_err("chacha20poly1305_aad failed %d", rc);
+               esp_log_err("ChaChaPoly chacha20poly1305_aad failed %d, SPI 0x%08x",
+                                       rc, ntohl(sav->spi));
                return rc;
        }
 
@@ -337,7 +383,8 @@ esp_chachapoly_encrypt(struct mbuf *m, // head of mbuf chain
                                                                          len, sp, sp);
                if (rc != 0) {
                        m_freem(m);
-                       esp_log_err("chacha20poly1305_encrypt failed %d", rc);
+                       esp_log_err("ChaChaPoly chacha20poly1305_encrypt failed %d, SPI 0x%08x",
+                                               rc, ntohl(sav->spi));
                        return rc;
                }
 
@@ -347,7 +394,8 @@ esp_chachapoly_encrypt(struct mbuf *m, // head of mbuf chain
        }
        if (s == NULL && soff != m->m_pkthdr.len) {
                m_freem(m);
-               esp_log_err("not enough mbufs %d %d", soff, m->m_pkthdr.len);
+               esp_log_err("ChaChaPoly not enough mbufs %d %d, SPI 0x%08x",
+                                       soff, m->m_pkthdr.len, ntohl(sav->spi));
                return EFBIG;
        }
        return 0;
@@ -366,35 +414,36 @@ esp_chachapoly_decrypt(struct mbuf *m, // head of mbuf chain
        uint8_t *sp; // buffer of a given encryption round
        size_t len; // length of a given encryption round
        const int32_t ivoff = (int32_t)off + (int32_t)sizeof(struct newesp); // IV offset
-       int32_t bodyoff; // body offset
+       const int32_t bodyoff = ivoff + ivlen; // body offset
        int rc = 0; // return code of corecrypto operations
        struct newesp esp_hdr; // ESP header for AAD
        _Static_assert(sizeof(esp_hdr) == 8, "Bad size");
-       uint8_t nonce[ESP_CHACHAPOLY_NONCE_LEN];
+       uint32_t nonce[ESP_CHACHAPOLY_NONCE_LEN / 4]; // ensure 32bit alignment
+       _Static_assert(sizeof(nonce) == ESP_CHACHAPOLY_NONCE_LEN, "Bad nonce length");
        esp_chachapoly_ctx_t esp_ccp_ctx;
 
        ESP_CHECK_ARG(m);
        ESP_CHECK_ARG(sav);
-       if (ivlen != ESP_CHACHAPOLY_IV_LEN) {
+
+       esp_ccp_ctx = (esp_chachapoly_ctx_t)sav->sched;
+
+       if (ivlen != (esp_ccp_ctx->ccp_implicit_iv ? 0 : ESP_CHACHAPOLY_IV_LEN)) {
                m_freem(m);
-               esp_log_err("Invalid ivlen %u", ivlen);
+               esp_log_err("ChaChaPoly Invalid ivlen %u, SPI 0x%08x",
+                                       ivlen, ntohl(sav->spi));
                return EINVAL;
        }
-       if (sav->ivlen != ESP_CHACHAPOLY_IV_LEN) {
+       if (sav->ivlen != ivlen) {
                m_freem(m);
-               esp_log_err("Invalid sav->ivlen %u", sav->ivlen);
+               esp_log_err("ChaChaPoly Invalid sav->ivlen %u, SPI 0x%08x",
+                                       sav->ivlen, ntohl(sav->spi));
                return EINVAL;
        }
 
-       esp_ccp_ctx = (esp_chachapoly_ctx_t)sav->sched;
-       if (esp_ccp_ctx->ccp_implicit_iv) {
-               bodyoff = ivoff;
-       } else {
-               bodyoff = ivoff + ivlen;
-       }
        // check if total packet length is enough to contain ESP + IV
        if (m->m_pkthdr.len < bodyoff) {
-               esp_packet_log_err("Packet too short %d < %zu", m->m_pkthdr.len, bodyoff);
+               esp_packet_log_err("ChaChaPoly Packet too short %d < %zu, SPI 0x%08x",
+                                                  m->m_pkthdr.len, bodyoff, ntohl(sav->spi));
                m_freem(m);
                return EINVAL;
        }
@@ -402,7 +451,8 @@ esp_chachapoly_decrypt(struct mbuf *m, // head of mbuf chain
        rc = chacha20poly1305_reset(&esp_ccp_ctx->ccp_ctx);
        if (rc != 0) {
                m_freem(m);
-               esp_log_err("chacha20poly1305_reset failed %d", rc);
+               esp_log_err("ChaChaPoly chacha20poly1305_reset failed %d, SPI 0x%08x",
+                                       rc, ntohl(sav->spi));
                return rc;
        }
 
@@ -413,20 +463,22 @@ esp_chachapoly_decrypt(struct mbuf *m, // head of mbuf chain
        memcpy(nonce, esp_ccp_ctx->ccp_salt, ESP_CHACHAPOLY_SALT_LEN);
        if (esp_ccp_ctx->ccp_implicit_iv) {
                // IV is implicit (4 zero bytes followed by the ESP sequence number)
-               memset(nonce + ESP_CHACHAPOLY_SALT_LEN, 0, 4);
-               memcpy(nonce + ESP_CHACHAPOLY_SALT_LEN + 4, &esp_hdr.esp_seq, sizeof(esp_hdr.esp_seq));
+               memset(((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN, 0, 4);
+               memcpy(((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN + 4,
+                          &esp_hdr.esp_seq, sizeof(esp_hdr.esp_seq));
                _Static_assert(4 + sizeof(esp_hdr.esp_seq) == ESP_CHACHAPOLY_IV_LEN, "Bad IV length");
        } else {
                // copy IV from packet
-               m_copydata(m, ivoff, ESP_CHACHAPOLY_IV_LEN, nonce + ESP_CHACHAPOLY_SALT_LEN);
+               m_copydata(m, ivoff, ESP_CHACHAPOLY_IV_LEN, ((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN);
        }
        _Static_assert(ESP_CHACHAPOLY_SALT_LEN + ESP_CHACHAPOLY_IV_LEN == sizeof(nonce),
                                   "Bad nonce length");
 
-       rc = chacha20poly1305_setnonce(&esp_ccp_ctx->ccp_ctx, nonce);
+       rc = chacha20poly1305_setnonce(&esp_ccp_ctx->ccp_ctx, (uint8_t *)nonce);
        if (rc != 0) {
                m_freem(m);
-               esp_log_err("chacha20poly1305_setnonce failed %d", rc);
+               esp_log_err("ChaChaPoly chacha20poly1305_setnonce failed %d, SPI 0x%08x",
+                                       rc, ntohl(sav->spi));
                return rc;
        }
        cc_clear(sizeof(nonce), nonce);
@@ -437,7 +489,8 @@ esp_chachapoly_decrypt(struct mbuf *m, // head of mbuf chain
                                                          (void *)&esp_hdr);
        if (rc != 0) {
                m_freem(m);
-               esp_log_err("chacha20poly1305_aad failed %d", rc);
+               esp_log_err("ChaChaPoly chacha20poly1305_aad failed %d, SPI 0x%08x",
+                                       rc, ntohl(sav->spi));
                return rc;
        }
 
@@ -464,7 +517,8 @@ esp_chachapoly_decrypt(struct mbuf *m, // head of mbuf chain
                                                                          len, sp, sp);
                if (rc != 0) {
                        m_freem(m);
-                       esp_packet_log_err("chacha20poly1305_decrypt failed %d", rc);
+                       esp_packet_log_err("chacha20poly1305_decrypt failed %d, SPI 0x%08x",
+                                                          rc, ntohl(sav->spi));
                        return rc;
                }
 
@@ -474,7 +528,8 @@ esp_chachapoly_decrypt(struct mbuf *m, // head of mbuf chain
        }
        if (s == NULL && soff != m->m_pkthdr.len) {
                m_freem(m);
-               esp_packet_log_err("not enough mbufs %d %d", soff, m->m_pkthdr.len);
+               esp_packet_log_err("not enough mbufs %d %d, SPI 0x%08x",
+                                                  soff, m->m_pkthdr.len, ntohl(sav->spi));
                return EFBIG;
        }
        return 0;