X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/b0d623f7f2ae71ed96e60569f61f9a9a27016e80..cb3231590a3c94ab4375e2228bd5e86b0cf1ad7e:/bsd/netinet6/esp_core.c diff --git a/bsd/netinet6/esp_core.c b/bsd/netinet6/esp_core.c index 3bae5bd18..17bd8e242 100644 --- a/bsd/netinet6/esp_core.c +++ b/bsd/netinet6/esp_core.c @@ -1,8 +1,8 @@ /* - * Copyright (c) 2008 Apple Inc. All rights reserved. + * Copyright (c) 2008-2019 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ - * + * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -11,10 +11,10 @@ * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. - * + * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. - * + * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, @@ -22,7 +22,7 @@ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. - * + * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ @@ -98,122 +98,186 @@ #include #endif #include +#include #include #include #include -#include -#include -#include +#include #include #include -#define DBG_LAYER_BEG NETDBG_CODE(DBG_NETIPSEC, 1) -#define DBG_LAYER_END NETDBG_CODE(DBG_NETIPSEC, 3) -#define DBG_FNC_ESPAUTH NETDBG_CODE(DBG_NETIPSEC, (8 << 8)) +#define DBG_LAYER_BEG NETDBG_CODE(DBG_NETIPSEC, 1) +#define DBG_LAYER_END NETDBG_CODE(DBG_NETIPSEC, 3) +#define DBG_FNC_ESPAUTH NETDBG_CODE(DBG_NETIPSEC, (8 << 8)) +#define MAX_SBUF_LEN 2000 extern lck_mtx_t *sadb_mutex; +os_log_t esp_mpkl_log_object = NULL; static int esp_null_mature(struct secasvar *); static int esp_null_decrypt(struct mbuf *, size_t, - struct secasvar *, const struct esp_algorithm *, int); + struct secasvar *, const struct esp_algorithm *, int); static int esp_null_encrypt(struct mbuf *, size_t, size_t, - struct secasvar *, const struct esp_algorithm *, int); + struct secasvar *, const struct esp_algorithm *, int); static int esp_descbc_mature(struct secasvar *); static int esp_descbc_ivlen(const struct esp_algorithm *, - struct secasvar *); + struct secasvar *); static int esp_des_schedule(const struct esp_algorithm *, - struct secasvar *); + struct secasvar *); static int esp_des_schedlen(const struct esp_algorithm *); static int esp_des_blockdecrypt(const struct esp_algorithm *, - struct secasvar *, u_int8_t *, u_int8_t *); + struct secasvar *, u_int8_t *, u_int8_t *); static int esp_des_blockencrypt(const struct esp_algorithm *, - struct secasvar *, u_int8_t *, u_int8_t *); + struct secasvar *, u_int8_t *, u_int8_t *); static int esp_cbc_mature(struct secasvar *); -#if ALLCRYPTO -static int esp_blowfish_schedule(const struct esp_algorithm *, - struct secasvar *); -static int esp_blowfish_schedlen(const struct esp_algorithm *); -static int esp_blowfish_blockdecrypt(const struct esp_algorithm *, - struct secasvar *, u_int8_t *, u_int8_t *); -static int esp_blowfish_blockencrypt(const struct esp_algorithm *, - struct secasvar *, u_int8_t *, u_int8_t *); -static int esp_cast128_schedule(const struct esp_algorithm *, - struct secasvar *); -static int esp_cast128_schedlen(const struct esp_algorithm *); -static int esp_cast128_blockdecrypt(const struct esp_algorithm *, - struct secasvar *, u_int8_t *, u_int8_t *); -static int esp_cast128_blockencrypt(const struct esp_algorithm *, - struct secasvar *, u_int8_t *, u_int8_t *); -#endif /* ALLCRYPTO */ static int esp_3des_schedule(const struct esp_algorithm *, - struct secasvar *); + struct secasvar *); static int esp_3des_schedlen(const struct esp_algorithm *); static int esp_3des_blockdecrypt(const struct esp_algorithm *, - struct secasvar *, u_int8_t *, u_int8_t *); + struct secasvar *, u_int8_t *, u_int8_t *); static int esp_3des_blockencrypt(const struct esp_algorithm *, - struct secasvar *, u_int8_t *, u_int8_t *); + struct secasvar *, u_int8_t *, u_int8_t *); static int esp_common_ivlen(const struct esp_algorithm *, - struct secasvar *); + struct secasvar *); static int esp_cbc_decrypt(struct mbuf *, size_t, - struct secasvar *, const struct esp_algorithm *, int); + struct secasvar *, const struct esp_algorithm *, int); static int esp_cbc_encrypt(struct mbuf *, size_t, size_t, - struct secasvar *, const struct esp_algorithm *, int); - -#define MAXIVLEN 16 - -static const struct esp_algorithm des_cbc = - { 8, -1, esp_descbc_mature, 64, 64, esp_des_schedlen, - "des-cbc", - esp_descbc_ivlen, esp_cbc_decrypt, - esp_cbc_encrypt, esp_des_schedule, - esp_des_blockdecrypt, esp_des_blockencrypt, }; -static const struct esp_algorithm des3_cbc = - { 8, 8, esp_cbc_mature, 192, 192, esp_3des_schedlen, - "3des-cbc", - esp_common_ivlen, esp_cbc_decrypt, - esp_cbc_encrypt, esp_3des_schedule, - esp_3des_blockdecrypt, esp_3des_blockencrypt, }; -static const struct esp_algorithm null_esp = - { 1, 0, esp_null_mature, 0, 2048, 0, "null", - esp_common_ivlen, esp_null_decrypt, - esp_null_encrypt, NULL, NULL, NULL }; -#if ALLCRYPTO -static const struct esp_algorithm blowfish_cbc = - { 8, 8, esp_cbc_mature, 40, 448, esp_blowfish_schedlen, "blowfish-cbc", - esp_common_ivlen, esp_cbc_decrypt, - esp_cbc_encrypt, esp_blowfish_schedule, - esp_blowfish_blockdecrypt, esp_blowfish_blockencrypt, }; -static const struct esp_algorithm cast128_cbc = - { 8, 8, esp_cbc_mature, 40, 128, esp_cast128_schedlen, - "cast128-cbc", - esp_common_ivlen, esp_cbc_decrypt, - esp_cbc_encrypt, esp_cast128_schedule, - esp_cast128_blockdecrypt, esp_cast128_blockencrypt, }; -#endif /* ALLCRYPTO */ -static const struct esp_algorithm aes_cbc = - { 16, 16, esp_cbc_mature, 128, 256, esp_aes_schedlen, - "aes-cbc", - esp_common_ivlen, esp_cbc_decrypt_aes, - esp_cbc_encrypt_aes, esp_aes_schedule, - 0, 0 }; + struct secasvar *, const struct esp_algorithm *, int); +static int esp_gcm_mature(struct secasvar *); + +#define MAXIVLEN 16 + +#define ESP_AESGCM_KEYLEN128 160 // 16-bytes key + 4 bytes salt +#define ESP_AESGCM_KEYLEN192 224 // 24-bytes key + 4 bytes salt +#define ESP_AESGCM_KEYLEN256 288 // 32-bytes key + 4 bytes salt + +static const struct esp_algorithm des_cbc = { + .padbound = 8, + .ivlenval = -1, + .mature = esp_descbc_mature, + .keymin = 64, + .keymax = 64, + .schedlen = esp_des_schedlen, + .name = "des-cbc", + .ivlen = esp_descbc_ivlen, + .decrypt = esp_cbc_decrypt, + .encrypt = esp_cbc_encrypt, + .schedule = esp_des_schedule, + .blockdecrypt = esp_des_blockdecrypt, + .blockencrypt = esp_des_blockencrypt, + .icvlen = 0, + .finalizedecrypt = NULL, + .finalizeencrypt = NULL +}; + +static const struct esp_algorithm des3_cbc = { + .padbound = 8, + .ivlenval = 8, + .mature = esp_cbc_mature, + .keymin = 192, + .keymax = 192, + .schedlen = esp_3des_schedlen, + .name = "3des-cbc", + .ivlen = esp_common_ivlen, + .decrypt = esp_cbc_decrypt, + .encrypt = esp_cbc_encrypt, + .schedule = esp_3des_schedule, + .blockdecrypt = esp_3des_blockdecrypt, + .blockencrypt = esp_3des_blockencrypt, + .icvlen = 0, + .finalizedecrypt = NULL, + .finalizeencrypt = NULL +}; + +static const struct esp_algorithm null_esp = { + .padbound = 1, + .ivlenval = 0, + .mature = esp_null_mature, + .keymin = 0, + .keymax = 2048, + .schedlen = NULL, + .name = "null", + .ivlen = esp_common_ivlen, + .decrypt = esp_null_decrypt, + .encrypt = esp_null_encrypt, + .schedule = NULL, + .blockdecrypt = NULL, + .blockencrypt = NULL, + .icvlen = 0, + .finalizedecrypt = NULL, + .finalizeencrypt = NULL +}; + +static const struct esp_algorithm aes_cbc = { + .padbound = 16, + .ivlenval = 16, + .mature = esp_cbc_mature, + .keymin = 128, + .keymax = 256, + .schedlen = esp_aes_schedlen, + .name = "aes-cbc", + .ivlen = esp_common_ivlen, + .decrypt = esp_cbc_decrypt_aes, + .encrypt = esp_cbc_encrypt_aes, + .schedule = esp_aes_schedule, + .blockdecrypt = NULL, + .blockencrypt = NULL, + .icvlen = 0, + .finalizedecrypt = NULL, + .finalizeencrypt = NULL +}; + +static const struct esp_algorithm aes_gcm = { + .padbound = 4, + .ivlenval = 8, + .mature = esp_gcm_mature, + .keymin = ESP_AESGCM_KEYLEN128, + .keymax = ESP_AESGCM_KEYLEN256, + .schedlen = esp_gcm_schedlen, + .name = "aes-gcm", + .ivlen = esp_common_ivlen, + .decrypt = esp_gcm_decrypt_aes, + .encrypt = esp_gcm_encrypt_aes, + .schedule = esp_gcm_schedule, + .blockdecrypt = NULL, + .blockencrypt = NULL, + .icvlen = 16, + .finalizedecrypt = esp_gcm_decrypt_finalize, + .finalizeencrypt = esp_gcm_encrypt_finalize +}; + +static const struct esp_algorithm chacha_poly = { + .padbound = ESP_CHACHAPOLY_PAD_BOUND, + .ivlenval = ESP_CHACHAPOLY_IV_LEN, + .mature = esp_chachapoly_mature, + .keymin = ESP_CHACHAPOLY_KEYBITS_WITH_SALT, + .keymax = ESP_CHACHAPOLY_KEYBITS_WITH_SALT, + .schedlen = esp_chachapoly_schedlen, + .name = "chacha-poly", + .ivlen = esp_chachapoly_ivlen, + .decrypt = esp_chachapoly_decrypt, + .encrypt = esp_chachapoly_encrypt, + .schedule = esp_chachapoly_schedule, + .blockdecrypt = NULL, + .blockencrypt = NULL, + .icvlen = ESP_CHACHAPOLY_ICV_LEN, + .finalizedecrypt = esp_chachapoly_decrypt_finalize, + .finalizeencrypt = esp_chachapoly_encrypt_finalize +}; static const struct esp_algorithm *esp_algorithms[] = { &des_cbc, &des3_cbc, &null_esp, -#if ALLCRYPTO - &blowfish_cbc, - &cast128_cbc, -#endif /* ALLCRYPTO */ - &aes_cbc + &aes_cbc, + &aes_gcm, + &chacha_poly, }; const struct esp_algorithm * -esp_algorithm_lookup(idx) - int idx; +esp_algorithm_lookup(int idx) { - switch (idx) { case SADB_EALG_DESCBC: return &des_cbc; @@ -221,39 +285,36 @@ esp_algorithm_lookup(idx) return &des3_cbc; case SADB_EALG_NULL: return &null_esp; -#if ALLCRYPTO - case SADB_X_EALG_BLOWFISHCBC: - return &blowfish_cbc; - case SADB_X_EALG_CAST128CBC: - return &cast128_cbc; -#endif /* ALLCRYPTO */ case SADB_X_EALG_RIJNDAELCBC: return &aes_cbc; + case SADB_X_EALG_AES_GCM: + return &aes_gcm; + case SADB_X_EALG_CHACHA20POLY1305: + return &chacha_poly; default: return NULL; } } int -esp_max_ivlen() +esp_max_ivlen(void) { int idx; int ivlen; ivlen = 0; - for (idx = 0; idx < sizeof(esp_algorithms)/sizeof(esp_algorithms[0]); - idx++) { - if (esp_algorithms[idx]->ivlenval > ivlen) + for (idx = 0; idx < sizeof(esp_algorithms) / sizeof(esp_algorithms[0]); + idx++) { + if (esp_algorithms[idx]->ivlenval > ivlen) { ivlen = esp_algorithms[idx]->ivlenval; + } } return ivlen; } int -esp_schedule(algo, sav) - const struct esp_algorithm *algo; - struct secasvar *sav; +esp_schedule(const struct esp_algorithm *algo, struct secasvar *sav) { int error; @@ -273,12 +334,24 @@ esp_schedule(algo, sav) lck_mtx_unlock(sadb_mutex); return 0; } + + /* prevent disallowed implicit IV */ + if (((sav->flags & SADB_X_EXT_IIV) != 0) && + (sav->alg_enc != SADB_X_EALG_AES_GCM) && + (sav->alg_enc != SADB_X_EALG_CHACHA20POLY1305)) { + ipseclog((LOG_ERR, + "esp_schedule %s: implicit IV not allowed\n", + algo->name)); + lck_mtx_unlock(sadb_mutex); + return EINVAL; + } + /* no schedule necessary */ if (!algo->schedule || !algo->schedlen) { lck_mtx_unlock(sadb_mutex); return 0; } - + sav->schedlen = (*algo->schedlen)(algo); if ((signed) sav->schedlen < 0) { lck_mtx_unlock(sadb_mutex); @@ -310,7 +383,6 @@ static int esp_null_mature( __unused struct secasvar *sav) { - /* anything is okay */ return 0; } @@ -318,31 +390,28 @@ esp_null_mature( static int esp_null_decrypt( __unused struct mbuf *m, - __unused size_t off, /* offset to ESP header */ + __unused size_t off, /* offset to ESP header */ __unused struct secasvar *sav, __unused const struct esp_algorithm *algo, __unused int ivlen) { - return 0; /* do nothing */ } static int esp_null_encrypt( __unused struct mbuf *m, - __unused size_t off, /* offset to ESP header */ - __unused size_t plen, /* payload length (to be encrypted) */ + __unused size_t off, /* offset to ESP header */ + __unused size_t plen, /* payload length (to be encrypted) */ __unused struct secasvar *sav, __unused const struct esp_algorithm *algo, __unused int ivlen) { - return 0; /* do nothing */ } static int -esp_descbc_mature(sav) - struct secasvar *sav; +esp_descbc_mature(struct secasvar *sav) { const struct esp_algorithm *algo; @@ -387,13 +456,15 @@ esp_descbc_ivlen( __unused const struct esp_algorithm *algo, struct secasvar *sav) { - - if (!sav) + if (!sav) { return 8; - if ((sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_IV4B)) + } + if ((sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_IV4B)) { return 4; - if (!(sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_DERIV)) + } + if (!(sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_DERIV)) { return 4; + } return 8; } @@ -401,8 +472,7 @@ static int esp_des_schedlen( __unused const struct esp_algorithm *algo) { - - return sizeof(des_key_schedule); + return sizeof(des_ecb_key_schedule); } static int @@ -410,13 +480,13 @@ esp_des_schedule( __unused const struct esp_algorithm *algo, struct secasvar *sav) { - - lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED); - if (des_key_sched((des_cblock *)_KEYBUF(sav->key_enc), - *(des_key_schedule *)sav->sched)) + LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED); + if (des_ecb_key_sched((des_cblock *)_KEYBUF(sav->key_enc), + (des_ecb_key_schedule *)sav->sched)) { return EINVAL; - else + } else { return 0; + } } static int @@ -426,12 +496,10 @@ esp_des_blockdecrypt( u_int8_t *s, u_int8_t *d) { - /* assumption: d has a good alignment */ bcopy(s, d, sizeof(DES_LONG) * 2); - des_ecb_encrypt((des_cblock *)d, (des_cblock *)d, - *(des_key_schedule *)sav->sched, DES_DECRYPT); - return 0; + return des_ecb_encrypt((des_cblock *)d, (des_cblock *)d, + (des_ecb_key_schedule *)sav->sched, DES_DECRYPT); } static int @@ -441,17 +509,14 @@ esp_des_blockencrypt( u_int8_t *s, u_int8_t *d) { - /* assumption: d has a good alignment */ bcopy(s, d, sizeof(DES_LONG) * 2); - des_ecb_encrypt((des_cblock *)d, (des_cblock *)d, - *(des_key_schedule *)sav->sched, DES_ENCRYPT); - return 0; + return des_ecb_encrypt((des_cblock *)d, (des_cblock *)d, + (des_ecb_key_schedule *)sav->sched, DES_ENCRYPT); } static int -esp_cbc_mature(sav) - struct secasvar *sav; +esp_cbc_mature(struct secasvar *sav) { int keylen; const struct esp_algorithm *algo; @@ -475,7 +540,7 @@ esp_cbc_mature(sav) algo = esp_algorithm_lookup(sav->alg_enc); if (!algo) { ipseclog((LOG_ERR, - "esp_cbc_mature %s: unsupported algorithm.\n", algo->name)); + "esp_cbc_mature: unsupported algorithm.\n")); return 1; } @@ -498,9 +563,6 @@ esp_cbc_mature(sav) return 1; } break; - case SADB_X_EALG_BLOWFISHCBC: - case SADB_X_EALG_CAST128CBC: - break; case SADB_X_EALG_RIJNDAELCBC: /* allows specific key sizes only */ if (!(keylen == 128 || keylen == 192 || keylen == 256)) { @@ -515,123 +577,71 @@ esp_cbc_mature(sav) return 0; } -#if ALLCRYPTO static int -esp_blowfish_schedlen( - __unused const struct esp_algorithm *algo) +esp_gcm_mature(struct secasvar *sav) { + int keylen; + const struct esp_algorithm *algo; - return sizeof(BF_KEY); -} - -static int -esp_blowfish_schedule( - __unused const struct esp_algorithm *algo, - struct secasvar *sav) -{ - - lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED); - BF_set_key((BF_KEY *)sav->sched, _KEYLEN(sav->key_enc), - (u_int8_t *) _KEYBUF(sav->key_enc)); - return 0; -} - -static int -esp_blowfish_blockdecrypt( - __unused const struct esp_algorithm *algo, - struct secasvar *sav, - u_int8_t *s, - u_int8_t *d) -{ - /* HOLY COW! BF_decrypt() takes values in host byteorder */ - BF_LONG t[2]; - - bcopy(s, t, sizeof(t)); - t[0] = ntohl(t[0]); - t[1] = ntohl(t[1]); - BF_decrypt(t, (BF_KEY *)sav->sched); - t[0] = htonl(t[0]); - t[1] = htonl(t[1]); - bcopy(t, d, sizeof(t)); - return 0; -} - -static int -esp_blowfish_blockencrypt( - __unused const struct esp_algorithm *algo, - struct secasvar *sav, - u_int8_t *s, - u_int8_t *d) -{ - /* HOLY COW! BF_encrypt() takes values in host byteorder */ - BF_LONG t[2]; - - bcopy(s, t, sizeof(t)); - t[0] = ntohl(t[0]); - t[1] = ntohl(t[1]); - BF_encrypt(t, (BF_KEY *)sav->sched); - t[0] = htonl(t[0]); - t[1] = htonl(t[1]); - bcopy(t, d, sizeof(t)); - return 0; -} - -static int -esp_cast128_schedlen( - __unused const struct esp_algorithm *algo) -{ - - return sizeof(u_int32_t) * 32; -} - -static int -esp_cast128_schedule( - __unused const struct esp_algorithm *algo, - struct secasvar *sav) -{ - lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED); - set_cast128_subkey((u_int32_t *)sav->sched, (u_int8_t *) _KEYBUF(sav->key_enc), - _KEYLEN(sav->key_enc)); - return 0; -} + if (sav->flags & SADB_X_EXT_OLD) { + ipseclog((LOG_ERR, + "esp_gcm_mature: algorithm incompatible with esp-old\n")); + return 1; + } + if (sav->flags & SADB_X_EXT_DERIV) { + ipseclog((LOG_ERR, + "esp_gcm_mature: algorithm incompatible with derived\n")); + return 1; + } + if (sav->flags & SADB_X_EXT_IIV) { + ipseclog((LOG_ERR, + "esp_gcm_mature: implicit IV not currently implemented\n")); + return 1; + } -static int -esp_cast128_blockdecrypt( - __unused const struct esp_algorithm *algo, - struct secasvar *sav, - u_int8_t *s, - u_int8_t *d) -{ + if (!sav->key_enc) { + ipseclog((LOG_ERR, "esp_gcm_mature: no key is given.\n")); + return 1; + } - if (_KEYLEN(sav->key_enc) <= 80 / 8) - cast128_decrypt_round12(d, s, (u_int32_t *)sav->sched); - else - cast128_decrypt_round16(d, s, (u_int32_t *)sav->sched); - return 0; -} + algo = esp_algorithm_lookup(sav->alg_enc); + if (!algo) { + ipseclog((LOG_ERR, + "esp_gcm_mature: unsupported algorithm.\n")); + return 1; + } -static int -esp_cast128_blockencrypt( - __unused const struct esp_algorithm *algo, - struct secasvar *sav, - u_int8_t *s, - u_int8_t *d) -{ + keylen = sav->key_enc->sadb_key_bits; + if (keylen < algo->keymin || algo->keymax < keylen) { + ipseclog((LOG_ERR, + "esp_gcm_mature %s: invalid key length %d.\n", + algo->name, sav->key_enc->sadb_key_bits)); + return 1; + } + switch (sav->alg_enc) { + case SADB_X_EALG_AES_GCM: + /* allows specific key sizes only */ + if (!(keylen == ESP_AESGCM_KEYLEN128 || keylen == ESP_AESGCM_KEYLEN192 || keylen == ESP_AESGCM_KEYLEN256)) { + ipseclog((LOG_ERR, + "esp_gcm_mature %s: invalid key length %d.\n", + algo->name, keylen)); + return 1; + } + break; + default: + ipseclog((LOG_ERR, + "esp_gcm_mature %s: invalid algo %d.\n", sav->alg_enc)); + return 1; + } - if (_KEYLEN(sav->key_enc) <= 80 / 8) - cast128_encrypt_round12(d, s, (u_int32_t *)sav->sched); - else - cast128_encrypt_round16(d, s, (u_int32_t *)sav->sched); return 0; } -#endif /* ALLCRYPTO */ static int esp_3des_schedlen( __unused const struct esp_algorithm *algo) { - - return sizeof(des_key_schedule) * 3; + return sizeof(des3_ecb_key_schedule); } static int @@ -639,20 +649,14 @@ esp_3des_schedule( __unused const struct esp_algorithm *algo, struct secasvar *sav) { - int error; - des_key_schedule *p; - int i; - char *k; - - lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED); - p = (des_key_schedule *)sav->sched; - k = _KEYBUF(sav->key_enc); - for (i = 0; i < 3; i++) { - error = des_key_sched((des_cblock *)(k + 8 * i), p[i]); - if (error) - return EINVAL; + LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED); + + if (des3_ecb_key_sched((des_cblock *)_KEYBUF(sav->key_enc), + (des3_ecb_key_schedule *)sav->sched)) { + return EINVAL; + } else { + return 0; } - return 0; } static int @@ -662,14 +666,10 @@ esp_3des_blockdecrypt( u_int8_t *s, u_int8_t *d) { - des_key_schedule *p; - /* assumption: d has a good alignment */ - p = (des_key_schedule *)sav->sched; bcopy(s, d, sizeof(DES_LONG) * 2); - des_ecb3_encrypt((des_cblock *)d, (des_cblock *)d, - p[0], p[1], p[2], DES_DECRYPT); - return 0; + return des3_ecb_encrypt((des_cblock *)d, (des_cblock *)d, + (des3_ecb_key_schedule *)sav->sched, DES_DECRYPT); } static int @@ -679,14 +679,10 @@ esp_3des_blockencrypt( u_int8_t *s, u_int8_t *d) { - des_key_schedule *p; - /* assumption: d has a good alignment */ - p = (des_key_schedule *)sav->sched; bcopy(s, d, sizeof(DES_LONG) * 2); - des_ecb3_encrypt((des_cblock *)d, (des_cblock *)d, - p[0], p[1], p[2], DES_ENCRYPT); - return 0; + return des3_ecb_encrypt((des_cblock *)d, (des_cblock *)d, + (des3_ecb_key_schedule *)sav->sched, DES_ENCRYPT); } static int @@ -694,31 +690,27 @@ esp_common_ivlen( const struct esp_algorithm *algo, __unused struct secasvar *sav) { - - if (!algo) + if (!algo) { panic("esp_common_ivlen: unknown algorithm"); + } return algo->ivlenval; } static int -esp_cbc_decrypt(m, off, sav, algo, ivlen) - struct mbuf *m; - size_t off; - struct secasvar *sav; - const struct esp_algorithm *algo; - int ivlen; +esp_cbc_decrypt(struct mbuf *m, size_t off, struct secasvar *sav, + const struct esp_algorithm *algo, int ivlen) { struct mbuf *s; struct mbuf *d, *d0, *dp; - int soff, doff; /* offset from the head of chain, to head of this mbuf */ - int sn, dn; /* offset from the head of the mbuf, to meat */ + int soff, doff; /* offset from the head of chain, to head of this mbuf */ + int sn, dn; /* offset from the head of the mbuf, to meat */ size_t ivoff, bodyoff; - u_int8_t iv[MAXIVLEN], *ivp; - u_int8_t sbuf[MAXIVLEN], *sp; + u_int8_t iv[MAXIVLEN] __attribute__((aligned(4))), *ivp; + u_int8_t *sbuf = NULL, *sp, *sp_unaligned; u_int8_t *p, *q; struct mbuf *scut; int scutoff; - int i; + int i, result = 0; int blocklen; int derived; @@ -768,9 +760,9 @@ esp_cbc_decrypt(m, off, sav, algo, ivlen) m_copydata(m, ivoff, ivlen, (caddr_t) iv); /* extend iv */ - if (ivlen == blocklen) + if (ivlen == blocklen) { ; - else if (ivlen == 4 && blocklen == 8) { + } else if (ivlen == 4 && blocklen == 8) { bcopy(&iv[0], &iv[4], 4); iv[4] ^= 0xff; iv[5] ^= 0xff; @@ -817,9 +809,15 @@ esp_cbc_decrypt(m, off, sav, algo, ivlen) scutoff = sn; /* skip over empty mbuf */ - while (s && s->m_len == 0) + while (s && s->m_len == 0) { s = s->m_next; + } + // Allocate blocksized buffer for unaligned or non-contiguous access + sbuf = (u_int8_t *)_MALLOC(blocklen, M_SECA, M_DONTWAIT); + if (sbuf == NULL) { + return ENOBUFS; + } while (soff < m->m_pkthdr.len) { /* source */ if (sn + blocklen <= s->m_len) { @@ -833,8 +831,9 @@ esp_cbc_decrypt(m, off, sav, algo, ivlen) /* destination */ if (!d || dn + blocklen > d->m_len) { - if (d) + if (d) { dp = d; + } MGET(d, M_DONTWAIT, MT_DATA); i = m->m_pkthdr.len - (soff + sn); if (d && i > MLEN) { @@ -846,36 +845,63 @@ esp_cbc_decrypt(m, off, sav, algo, ivlen) } if (!d) { m_freem(m); - if (d0) + if (d0) { m_freem(d0); - return ENOBUFS; + } + result = ENOBUFS; + goto end; } - if (!d0) + if (!d0) { d0 = d; - if (dp) + } + if (dp) { dp->m_next = d; + } + + // try to make mbuf data aligned + if (!IPSEC_IS_P2ALIGNED(d->m_data)) { + m_adj(d, IPSEC_GET_P2UNALIGNED_OFS(d->m_data)); + } + d->m_len = 0; d->m_len = (M_TRAILINGSPACE(d) / blocklen) * blocklen; - if (d->m_len > i) + if (d->m_len > i) { d->m_len = i; + } dn = 0; } /* decrypt */ + // check input pointer alignment and use a separate aligned buffer (if sp is unaligned on 4-byte boundary). + if (IPSEC_IS_P2ALIGNED(sp)) { + sp_unaligned = NULL; + } else { + sp_unaligned = sp; + sp = sbuf; + memcpy(sp, sp_unaligned, blocklen); + } + // no need to check output pointer alignment (*algo->blockdecrypt)(algo, sav, sp, mtod(d, u_int8_t *) + dn); + // update unaligned pointers + if (!IPSEC_IS_P2ALIGNED(sp_unaligned)) { + sp = sp_unaligned; + } + /* xor */ p = ivp ? ivp : iv; q = mtod(d, u_int8_t *) + dn; - for (i = 0; i < blocklen; i++) + for (i = 0; i < blocklen; i++) { q[i] ^= p[i]; + } /* next iv */ if (sp == sbuf) { bcopy(sbuf, iv, blocklen); ivp = NULL; - } else + } else { ivp = sp; + } sn += blocklen; dn += blocklen; @@ -894,9 +920,12 @@ esp_cbc_decrypt(m, off, sav, algo, ivlen) /* just in case */ bzero(iv, sizeof(iv)); - bzero(sbuf, sizeof(sbuf)); - - return 0; + bzero(sbuf, blocklen); +end: + if (sbuf != NULL) { + FREE(sbuf, M_SECA); + } + return result; } static int @@ -910,15 +939,15 @@ esp_cbc_encrypt( { struct mbuf *s; struct mbuf *d, *d0, *dp; - int soff, doff; /* offset from the head of chain, to head of this mbuf */ - int sn, dn; /* offset from the head of the mbuf, to meat */ + int soff, doff; /* offset from the head of chain, to head of this mbuf */ + int sn, dn; /* offset from the head of the mbuf, to meat */ size_t ivoff, bodyoff; - u_int8_t iv[MAXIVLEN], *ivp; - u_int8_t sbuf[MAXIVLEN], *sp; + u_int8_t iv[MAXIVLEN] __attribute__((aligned(4))), *ivp; + u_int8_t *sbuf = NULL, *sp, *sp_unaligned; u_int8_t *p, *q; struct mbuf *scut; int scutoff; - int i; + int i, result = 0; int blocklen; int derived; @@ -965,18 +994,18 @@ esp_cbc_encrypt( } /* put iv into the packet. if we are in derived mode, use seqno. */ - if (derived) + if (derived) { m_copydata(m, ivoff, ivlen, (caddr_t) iv); - else { + } else { bcopy(sav->iv, iv, ivlen); /* maybe it is better to overwrite dest, not source */ m_copyback(m, ivoff, ivlen, (caddr_t) iv); } /* extend iv */ - if (ivlen == blocklen) + if (ivlen == blocklen) { ; - else if (ivlen == 4 && blocklen == 8) { + } else if (ivlen == 4 && blocklen == 8) { bcopy(&iv[0], &iv[4], 4); iv[4] ^= 0xff; iv[5] ^= 0xff; @@ -1023,9 +1052,15 @@ esp_cbc_encrypt( scutoff = sn; /* skip over empty mbuf */ - while (s && s->m_len == 0) + while (s && s->m_len == 0) { s = s->m_next; + } + // Allocate blocksized buffer for unaligned or non-contiguous access + sbuf = (u_int8_t *)_MALLOC(blocklen, M_SECA, M_DONTWAIT); + if (sbuf == NULL) { + return ENOBUFS; + } while (soff < m->m_pkthdr.len) { /* source */ if (sn + blocklen <= s->m_len) { @@ -1039,8 +1074,9 @@ esp_cbc_encrypt( /* destination */ if (!d || dn + blocklen > d->m_len) { - if (d) + if (d) { dp = d; + } MGET(d, M_DONTWAIT, MT_DATA); i = m->m_pkthdr.len - (soff + sn); if (d && i > MLEN) { @@ -1052,30 +1088,56 @@ esp_cbc_encrypt( } if (!d) { m_freem(m); - if (d0) + if (d0) { m_freem(d0); - return ENOBUFS; + } + result = ENOBUFS; + goto end; } - if (!d0) + if (!d0) { d0 = d; - if (dp) + } + if (dp) { dp->m_next = d; + } + + // try to make mbuf data aligned + if (!IPSEC_IS_P2ALIGNED(d->m_data)) { + m_adj(d, IPSEC_GET_P2UNALIGNED_OFS(d->m_data)); + } + d->m_len = 0; d->m_len = (M_TRAILINGSPACE(d) / blocklen) * blocklen; - if (d->m_len > i) + if (d->m_len > i) { d->m_len = i; + } dn = 0; } /* xor */ p = ivp ? ivp : iv; q = sp; - for (i = 0; i < blocklen; i++) + for (i = 0; i < blocklen; i++) { q[i] ^= p[i]; + } /* encrypt */ + // check input pointer alignment and use a separate aligned buffer (if sp is not aligned on 4-byte boundary). + if (IPSEC_IS_P2ALIGNED(sp)) { + sp_unaligned = NULL; + } else { + sp_unaligned = sp; + sp = sbuf; + memcpy(sp, sp_unaligned, blocklen); + } + // no need to check output pointer alignment (*algo->blockencrypt)(algo, sav, sp, mtod(d, u_int8_t *) + dn); + // update unaligned pointers + if (!IPSEC_IS_P2ALIGNED(sp_unaligned)) { + sp = sp_unaligned; + } + /* next iv */ ivp = mtod(d, u_int8_t *) + dn; @@ -1096,28 +1158,31 @@ esp_cbc_encrypt( /* just in case */ bzero(iv, sizeof(iv)); - bzero(sbuf, sizeof(sbuf)); + bzero(sbuf, blocklen); key_sa_stir_iv(sav); - - return 0; +end: + if (sbuf != NULL) { + FREE(sbuf, M_SECA); + } + return result; } /*------------------------------------------------------------*/ /* does not free m0 on error */ int -esp_auth(m0, skip, length, sav, sum) - struct mbuf *m0; - size_t skip; /* offset to ESP header */ - size_t length; /* payload length */ - struct secasvar *sav; - u_char *sum; +esp_auth( + struct mbuf *m0, + size_t skip, /* offset to ESP header */ + size_t length, /* payload length */ + struct secasvar *sav, + u_char *sum) { struct mbuf *m; size_t off; struct ah_algorithm_state s; - u_char sumbuf[AH_MAXSUMSIZE]; + u_char sumbuf[AH_MAXSUMSIZE] __attribute__((aligned(4))); const struct ah_algorithm *algo; size_t siz; int error; @@ -1133,19 +1198,19 @@ esp_auth(m0, skip, length, sav, sum) return EINVAL; } - KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_START, skip,length,0,0,0); + KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_START, skip, length, 0, 0, 0); /* * length of esp part (excluding authentication data) must be 4n, * since nexthdr must be at offset 4n+3. */ if (length % 4) { ipseclog((LOG_ERR, "esp_auth: length is not multiple of 4\n")); - KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 1,0,0,0,0); + KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 1, 0, 0, 0, 0); return EINVAL; } if (!sav) { ipseclog((LOG_DEBUG, "esp_auth: NULL SA passed\n")); - KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 2,0,0,0,0); + KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 2, 0, 0, 0, 0); return EINVAL; } algo = ah_algorithm_lookup(sav->alg_auth); @@ -1153,7 +1218,7 @@ esp_auth(m0, skip, length, sav, sum) ipseclog((LOG_ERR, "esp_auth: bad ESP auth algorithm passed: %d\n", sav->alg_auth)); - KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 3,0,0,0,0); + KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 3, 0, 0, 0, 0); return EINVAL; } @@ -1165,14 +1230,15 @@ esp_auth(m0, skip, length, sav, sum) ipseclog((LOG_DEBUG, "esp_auth: AH_MAXSUMSIZE is too small: siz=%lu\n", (u_int32_t)siz)); - KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 4,0,0,0,0); + KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 4, 0, 0, 0, 0); return EINVAL; } /* skip the header */ while (skip) { - if (!m) + if (!m) { panic("mbuf chain?"); + } if (m->m_len <= skip) { skip -= m->m_len; m = m->m_next; @@ -1185,16 +1251,17 @@ esp_auth(m0, skip, length, sav, sum) error = (*algo->init)(&s, sav); if (error) { - KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 5,0,0,0,0); + KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 5, 0, 0, 0, 0); return error; } while (0 < length) { - if (!m) + if (!m) { panic("mbuf chain?"); + } if (m->m_len - off < length) { (*algo->update)(&s, (caddr_t)(mtod(m, u_char *) + off), - m->m_len - off); + m->m_len - off); length -= m->m_len - off; m = m->m_next; off = 0; @@ -1203,8 +1270,27 @@ esp_auth(m0, skip, length, sav, sum) break; } } - (*algo->result)(&s, (caddr_t) sumbuf); - bcopy(sumbuf, sum, siz); /*XXX*/ - KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 6,0,0,0,0); + (*algo->result)(&s, (caddr_t) sumbuf, sizeof(sumbuf)); + bcopy(sumbuf, sum, siz); /*XXX*/ + KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 6, 0, 0, 0, 0); return 0; } + +void +esp_init(void) +{ + static int esp_initialized = 0; + + if (esp_initialized) { + return; + } + + esp_initialized = 1; + + esp_mpkl_log_object = MPKL_CREATE_LOGOBJECT("com.apple.xnu.esp"); + if (esp_mpkl_log_object == NULL) { + panic("MPKL_CREATE_LOGOBJECT for ESP failed"); + } + + return; +}