X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/d26ffc64f583ab2d29df48f13518685602bc8832..d9a64523371fa019c4575bb400cbbc3a50ac9903:/bsd/netinet6/esp_chachapoly.c diff --git a/bsd/netinet6/esp_chachapoly.c b/bsd/netinet6/esp_chachapoly.c index 0970f6983..2c68e6f07 100644 --- a/bsd/netinet6/esp_chachapoly.c +++ b/bsd/netinet6/esp_chachapoly.c @@ -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;