X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/9bccf70c0258c7cac2dcb80011b2a964d884c552..04b8595b18b1b41ac7a206e4b3d51a635f8413d7:/bsd/netinet6/esp_core.c diff --git a/bsd/netinet6/esp_core.c b/bsd/netinet6/esp_core.c index 0cdede849..b5236fdd7 100644 --- a/bsd/netinet6/esp_core.c +++ b/bsd/netinet6/esp_core.c @@ -1,4 +1,32 @@ -/* $FreeBSD: src/sys/netinet6/esp_core.c,v 1.1.2.2 2001/07/03 11:01:49 ume Exp $ */ +/* + * Copyright (c) 2008 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 + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * 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, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * 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@ + */ + +/* $FreeBSD: src/sys/netinet6/esp_core.c,v 1.1.2.4 2002/03/26 10:12:29 ume Exp $ */ /* $KAME: esp_core.c,v 1.50 2000/11/02 12:27:38 itojun Exp $ */ /* @@ -44,6 +72,8 @@ #include #include +#include + #include #include @@ -71,106 +101,93 @@ #include #include #include -#include -#include -#include +#include #include -static int esp_null_mature __P((struct secasvar *)); -static int esp_null_decrypt __P((struct mbuf *, size_t, - struct secasvar *, const struct esp_algorithm *, int)); -static int esp_null_encrypt __P((struct mbuf *, size_t, size_t, - struct secasvar *, const struct esp_algorithm *, int)); -static int esp_descbc_mature __P((struct secasvar *)); -static int esp_descbc_ivlen __P((const struct esp_algorithm *, - struct secasvar *)); -static int esp_des_schedule __P((const struct esp_algorithm *, - struct secasvar *)); -static int esp_des_schedlen __P((const struct esp_algorithm *)); -static int esp_des_blockdecrypt __P((const struct esp_algorithm *, - struct secasvar *, u_int8_t *, u_int8_t *)); -static int esp_des_blockencrypt __P((const struct esp_algorithm *, - struct secasvar *, u_int8_t *, u_int8_t *)); -static int esp_cbc_mature __P((struct secasvar *)); -static int esp_blowfish_schedule __P((const struct esp_algorithm *, - struct secasvar *)); -static int esp_blowfish_schedlen __P((const struct esp_algorithm *)); -static int esp_blowfish_blockdecrypt __P((const struct esp_algorithm *, - struct secasvar *, u_int8_t *, u_int8_t *)); -static int esp_blowfish_blockencrypt __P((const struct esp_algorithm *, - struct secasvar *, u_int8_t *, u_int8_t *)); -static int esp_cast128_schedule __P((const struct esp_algorithm *, - struct secasvar *)); -static int esp_cast128_schedlen __P((const struct esp_algorithm *)); -static int esp_cast128_blockdecrypt __P((const struct esp_algorithm *, - struct secasvar *, u_int8_t *, u_int8_t *)); -static int esp_cast128_blockencrypt __P((const struct esp_algorithm *, - struct secasvar *, u_int8_t *, u_int8_t *)); -static int esp_3des_schedule __P((const struct esp_algorithm *, - struct secasvar *)); -static int esp_3des_schedlen __P((const struct esp_algorithm *)); -static int esp_3des_blockdecrypt __P((const struct esp_algorithm *, - struct secasvar *, u_int8_t *, u_int8_t *)); -static int esp_3des_blockencrypt __P((const struct esp_algorithm *, - struct secasvar *, u_int8_t *, u_int8_t *)); -static int esp_common_ivlen __P((const struct esp_algorithm *, - struct secasvar *)); -static int esp_cbc_decrypt __P((struct mbuf *, size_t, - struct secasvar *, const struct esp_algorithm *, int)); -static int esp_cbc_encrypt __P((struct mbuf *, size_t, size_t, - struct secasvar *, const struct esp_algorithm *, int)); +#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 MAX_SBUF_LEN 2000 + +extern lck_mtx_t *sadb_mutex; + +static int esp_null_mature(struct secasvar *); +static int esp_null_decrypt(struct mbuf *, size_t, + 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); +static int esp_descbc_mature(struct secasvar *); +static int esp_descbc_ivlen(const struct esp_algorithm *, + struct secasvar *); +static int esp_des_schedule(const struct esp_algorithm *, + 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 *); +static int esp_des_blockencrypt(const struct esp_algorithm *, + struct secasvar *, u_int8_t *, u_int8_t *); +static int esp_cbc_mature(struct secasvar *); +static int esp_3des_schedule(const struct esp_algorithm *, + 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 *); +static int esp_3des_blockencrypt(const struct esp_algorithm *, + struct secasvar *, u_int8_t *, u_int8_t *); +static int esp_common_ivlen(const struct esp_algorithm *, + struct secasvar *); +static int esp_cbc_decrypt(struct mbuf *, size_t, + 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 esp_algorithms[] = { +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, }, + 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, }, + 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, }, - { 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, }, - { 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, }, - { 16, 16, esp_cbc_mature, 128, 256, esp_rijndael_schedlen, - "rijndael-cbc", - esp_common_ivlen, esp_cbc_decrypt, - esp_cbc_encrypt, esp_rijndael_schedule, - esp_rijndael_blockdecrypt, esp_rijndael_blockencrypt }, + esp_null_encrypt, NULL, NULL, NULL }; +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 }; + +static const struct esp_algorithm *esp_algorithms[] = { + &des_cbc, + &des3_cbc, + &null_esp, + &aes_cbc }; const struct esp_algorithm * esp_algorithm_lookup(idx) int idx; { - switch (idx) { case SADB_EALG_DESCBC: - return &esp_algorithms[0]; + return &des_cbc; case SADB_EALG_3DESCBC: - return &esp_algorithms[1]; + return &des3_cbc; case SADB_EALG_NULL: - return &esp_algorithms[2]; - case SADB_X_EALG_BLOWFISHCBC: - return &esp_algorithms[3]; - case SADB_X_EALG_CAST128CBC: - return &esp_algorithms[4]; + return &null_esp; case SADB_X_EALG_RIJNDAELCBC: - return &esp_algorithms[5]; + return &aes_cbc; default: return NULL; } @@ -185,8 +202,8 @@ esp_max_ivlen() ivlen = 0; for (idx = 0; idx < sizeof(esp_algorithms)/sizeof(esp_algorithms[0]); idx++) { - if (esp_algorithms[idx].ivlenval > ivlen) - ivlen = esp_algorithms[idx].ivlenval; + if (esp_algorithms[idx]->ivlenval > ivlen) + ivlen = esp_algorithms[idx]->ivlenval; } return ivlen; @@ -209,19 +226,29 @@ esp_schedule(algo, sav) return EINVAL; } + lck_mtx_lock(sadb_mutex); /* already allocated */ - if (sav->sched && sav->schedlen != 0) + if (sav->sched && sav->schedlen != 0) { + lck_mtx_unlock(sadb_mutex); return 0; + } /* no schedule necessary */ - if (!algo->schedule || !algo->schedlen) + if (!algo->schedule || !algo->schedlen) { + lck_mtx_unlock(sadb_mutex); return 0; - + } + sav->schedlen = (*algo->schedlen)(algo); - if (sav->schedlen < 0) + if ((signed) sav->schedlen < 0) { + lck_mtx_unlock(sadb_mutex); return EINVAL; + } + +//#### that malloc should be replaced by a saved buffer... sav->sched = _MALLOC(sav->schedlen, M_SECA, M_DONTWAIT); if (!sav->sched) { sav->schedlen = 0; + lck_mtx_unlock(sadb_mutex); return ENOBUFS; } @@ -229,16 +256,18 @@ esp_schedule(algo, sav) if (error) { ipseclog((LOG_ERR, "esp_schedule %s: error %d\n", algo->name, error)); + bzero(sav->sched, sav->schedlen); FREE(sav->sched, M_SECA); sav->sched = NULL; sav->schedlen = 0; } + lck_mtx_unlock(sadb_mutex); return error; } static int -esp_null_mature(sav) - struct secasvar *sav; +esp_null_mature( + __unused struct secasvar *sav) { /* anything is okay */ @@ -246,25 +275,25 @@ esp_null_mature(sav) } static int -esp_null_decrypt(m, off, sav, algo, ivlen) - struct mbuf *m; - size_t off; /* offset to ESP header */ - struct secasvar *sav; - const struct esp_algorithm *algo; - int ivlen; +esp_null_decrypt( + __unused struct mbuf *m, + __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(m, off, plen, sav, algo, ivlen) - struct mbuf *m; - size_t off; /* offset to ESP header */ - size_t plen; /* payload length (to be encrypted) */ - struct secasvar *sav; - const struct esp_algorithm *algo; - int ivlen; +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 struct secasvar *sav, + __unused const struct esp_algorithm *algo, + __unused int ivlen) { return 0; /* do nothing */ @@ -313,9 +342,9 @@ esp_descbc_mature(sav) } static int -esp_descbc_ivlen(algo, sav) - const struct esp_algorithm *algo; - struct secasvar *sav; +esp_descbc_ivlen( + __unused const struct esp_algorithm *algo, + struct secasvar *sav) { if (!sav) @@ -328,53 +357,51 @@ esp_descbc_ivlen(algo, sav) } static int -esp_des_schedlen(algo) - const struct esp_algorithm *algo; +esp_des_schedlen( + __unused const struct esp_algorithm *algo) { - - return sizeof(des_key_schedule); + return sizeof(des_ecb_key_schedule); } static int -esp_des_schedule(algo, sav) - const struct esp_algorithm *algo; - struct secasvar *sav; +esp_des_schedule( + __unused const struct esp_algorithm *algo, + struct secasvar *sav) { - 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 return 0; } static int -esp_des_blockdecrypt(algo, sav, s, d) - const struct esp_algorithm *algo; - struct secasvar *sav; - u_int8_t *s; - u_int8_t *d; +esp_des_blockdecrypt( + __unused const struct esp_algorithm *algo, + struct secasvar *sav, + 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); + (des_ecb_key_schedule *)sav->sched, DES_DECRYPT); return 0; } static int -esp_des_blockencrypt(algo, sav, s, d) - const struct esp_algorithm *algo; - struct secasvar *sav; - u_int8_t *s; - u_int8_t *d; +esp_des_blockencrypt( + __unused const struct esp_algorithm *algo, + struct secasvar *sav, + 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); + (des_ecb_key_schedule *)sav->sched, DES_ENCRYPT); return 0; } @@ -404,7 +431,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; } @@ -427,9 +454,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)) { @@ -445,181 +469,59 @@ esp_cbc_mature(sav) } static int -esp_blowfish_schedlen(algo) - const struct esp_algorithm *algo; -{ - - return sizeof(BF_KEY); -} - -static int -esp_blowfish_schedule(algo, sav) - const struct esp_algorithm *algo; - struct secasvar *sav; -{ - - BF_set_key((BF_KEY *)sav->sched, _KEYLEN(sav->key_enc), - _KEYBUF(sav->key_enc)); - return 0; -} - -static int -esp_blowfish_blockdecrypt(algo, sav, s, d) - 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, BF_DECRYPT); - t[0] = htonl(t[0]); - t[1] = htonl(t[1]); - bcopy(t, d, sizeof(t)); - return 0; -} - -static int -esp_blowfish_blockencrypt(algo, sav, s, d) - 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, BF_ENCRYPT); - t[0] = htonl(t[0]); - t[1] = htonl(t[1]); - bcopy(t, d, sizeof(t)); - return 0; -} - -static int -esp_cast128_schedlen(algo) - const struct esp_algorithm *algo; -{ - - return sizeof(u_int32_t) * 32; -} - -static int -esp_cast128_schedule(algo, sav) - const struct esp_algorithm *algo; - struct secasvar *sav; -{ - - set_cast128_subkey((u_int32_t *)sav->sched, _KEYBUF(sav->key_enc), - _KEYLEN(sav->key_enc)); - return 0; -} - -static int -esp_cast128_blockdecrypt(algo, sav, s, d) - const struct esp_algorithm *algo; - struct secasvar *sav; - u_int8_t *s; - u_int8_t *d; +esp_3des_schedlen( + __unused const struct esp_algorithm *algo) { - 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; + return sizeof(des3_ecb_key_schedule); } static int -esp_cast128_blockencrypt(algo, sav, s, d) - const struct esp_algorithm *algo; - struct secasvar *sav; - u_int8_t *s; - u_int8_t *d; +esp_3des_schedule( + __unused const struct esp_algorithm *algo, + struct secasvar *sav) { + lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED); - if (_KEYLEN(sav->key_enc) <= 80 / 8) - cast128_encrypt_round12(d, s, (u_int32_t *)sav->sched); + if (des3_ecb_key_sched((des_cblock *)_KEYBUF(sav->key_enc), + (des3_ecb_key_schedule *)sav->sched)) + return EINVAL; else - cast128_encrypt_round16(d, s, (u_int32_t *)sav->sched); - return 0; -} - -static int -esp_3des_schedlen(algo) - const struct esp_algorithm *algo; -{ - - return sizeof(des_key_schedule) * 3; -} - -static int -esp_3des_schedule(algo, sav) - const struct esp_algorithm *algo; - struct secasvar *sav; -{ - int error; - des_key_schedule *p; - int i; - char *k; - - 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; - } - return 0; + return 0; } static int -esp_3des_blockdecrypt(algo, sav, s, d) - const struct esp_algorithm *algo; - struct secasvar *sav; - u_int8_t *s; - u_int8_t *d; +esp_3des_blockdecrypt( + __unused const struct esp_algorithm *algo, + struct secasvar *sav, + 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_ecb_encrypt((des_cblock *)d, (des_cblock *)d, p[2], DES_DECRYPT); - des_ecb_encrypt((des_cblock *)d, (des_cblock *)d, p[1], DES_ENCRYPT); - des_ecb_encrypt((des_cblock *)d, (des_cblock *)d, p[0], DES_DECRYPT); + des3_ecb_encrypt((des_cblock *)d, (des_cblock *)d, + (des3_ecb_key_schedule *)sav->sched, DES_DECRYPT); return 0; } static int -esp_3des_blockencrypt(algo, sav, s, d) - const struct esp_algorithm *algo; - struct secasvar *sav; - u_int8_t *s; - u_int8_t *d; +esp_3des_blockencrypt( + __unused const struct esp_algorithm *algo, + struct secasvar *sav, + 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_ecb_encrypt((des_cblock *)d, (des_cblock *)d, p[0], DES_ENCRYPT); - des_ecb_encrypt((des_cblock *)d, (des_cblock *)d, p[1], DES_DECRYPT); - des_ecb_encrypt((des_cblock *)d, (des_cblock *)d, p[2], DES_ENCRYPT); + des3_ecb_encrypt((des_cblock *)d, (des_cblock *)d, + (des3_ecb_key_schedule *)sav->sched, DES_ENCRYPT); return 0; } static int -esp_common_ivlen(algo, sav) - const struct esp_algorithm *algo; - struct secasvar *sav; +esp_common_ivlen( + const struct esp_algorithm *algo, + __unused struct secasvar *sav) { if (!algo) @@ -637,15 +539,15 @@ esp_cbc_decrypt(m, off, sav, algo, 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; @@ -692,7 +594,7 @@ esp_cbc_decrypt(m, off, sav, algo, ivlen) } /* grab iv */ - m_copydata(m, ivoff, ivlen, iv); + m_copydata(m, ivoff, ivlen, (caddr_t) iv); /* extend iv */ if (ivlen == blocklen) @@ -713,7 +615,7 @@ esp_cbc_decrypt(m, off, sav, algo, ivlen) if (m->m_pkthdr.len < bodyoff) { ipseclog((LOG_ERR, "esp_cbc_decrypt %s: bad len %d/%lu\n", - algo->name, m->m_pkthdr.len, (unsigned long)bodyoff)); + algo->name, m->m_pkthdr.len, (u_int32_t)bodyoff)); m_freem(m); return EINVAL; } @@ -747,6 +649,10 @@ esp_cbc_decrypt(m, off, sav, algo, ivlen) 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) { @@ -754,7 +660,7 @@ esp_cbc_decrypt(m, off, sav, algo, ivlen) sp = mtod(s, u_int8_t *) + sn; } else { /* body is non-continuous */ - m_copydata(s, sn, blocklen, sbuf); + m_copydata(s, sn, blocklen, (caddr_t) sbuf); sp = sbuf; } @@ -775,12 +681,19 @@ esp_cbc_decrypt(m, off, sav, algo, ivlen) m_freem(m); if (d0) m_freem(d0); - return ENOBUFS; + result = ENOBUFS; + goto end; } if (!d0) d0 = d; 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) @@ -789,8 +702,22 @@ esp_cbc_decrypt(m, off, sav, algo, ivlen) } /* 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; @@ -813,10 +740,6 @@ esp_cbc_decrypt(m, off, sav, algo, ivlen) soff += s->m_len; s = s->m_next; } - - /* skip over empty mbuf */ - while (s && s->m_len == 0) - s = s->m_next; } m_freem(scut->m_next); @@ -825,31 +748,33 @@ 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 -esp_cbc_encrypt(m, off, plen, sav, algo, ivlen) - struct mbuf *m; - size_t off; - size_t plen; - struct secasvar *sav; - const struct esp_algorithm *algo; - int ivlen; +esp_cbc_encrypt( + struct mbuf *m, + size_t off, + __unused size_t plen, + 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; @@ -897,11 +822,11 @@ esp_cbc_encrypt(m, off, plen, sav, algo, ivlen) /* put iv into the packet. if we are in derived mode, use seqno. */ if (derived) - m_copydata(m, ivoff, ivlen, iv); + m_copydata(m, ivoff, ivlen, (caddr_t) iv); else { bcopy(sav->iv, iv, ivlen); /* maybe it is better to overwrite dest, not source */ - m_copyback(m, ivoff, ivlen, iv); + m_copyback(m, ivoff, ivlen, (caddr_t) iv); } /* extend iv */ @@ -923,14 +848,14 @@ esp_cbc_encrypt(m, off, plen, sav, algo, ivlen) if (m->m_pkthdr.len < bodyoff) { ipseclog((LOG_ERR, "esp_cbc_encrypt %s: bad len %d/%lu\n", - algo->name, m->m_pkthdr.len, (unsigned long)bodyoff)); + algo->name, m->m_pkthdr.len, (u_int32_t)bodyoff)); m_freem(m); return EINVAL; } if ((m->m_pkthdr.len - bodyoff) % blocklen) { ipseclog((LOG_ERR, "esp_cbc_encrypt %s: " "payload length must be multiple of %lu\n", - algo->name, (unsigned long)algo->padbound)); + algo->name, (u_int32_t)algo->padbound)); m_freem(m); return EINVAL; } @@ -957,6 +882,10 @@ esp_cbc_encrypt(m, off, plen, sav, algo, ivlen) 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) { @@ -964,7 +893,7 @@ esp_cbc_encrypt(m, off, plen, sav, algo, ivlen) sp = mtod(s, u_int8_t *) + sn; } else { /* body is non-continuous */ - m_copydata(s, sn, blocklen, sbuf); + m_copydata(s, sn, blocklen, (caddr_t) sbuf); sp = sbuf; } @@ -985,12 +914,19 @@ esp_cbc_encrypt(m, off, plen, sav, algo, ivlen) m_freem(m); if (d0) m_freem(d0); - return ENOBUFS; + result = ENOBUFS; + goto end; } if (!d0) d0 = d; 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) @@ -1005,8 +941,22 @@ esp_cbc_encrypt(m, off, plen, sav, algo, ivlen) 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; @@ -1019,10 +969,6 @@ esp_cbc_encrypt(m, off, plen, sav, algo, ivlen) soff += s->m_len; s = s->m_next; } - - /* skip over empty mbuf */ - while (s && s->m_len == 0) - s = s->m_next; } m_freem(scut->m_next); @@ -1031,11 +977,13 @@ esp_cbc_encrypt(m, off, plen, sav, algo, ivlen) /* 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; } /*------------------------------------------------------------*/ @@ -1052,7 +1000,7 @@ esp_auth(m0, skip, length, sav, 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; @@ -1067,16 +1015,20 @@ esp_auth(m0, skip, length, sav, sum) "esp_auth: mbuf length < skip + length\n")); return EINVAL; } + + 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); 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); return EINVAL; } algo = ah_algorithm_lookup(sav->alg_auth); @@ -1084,6 +1036,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); return EINVAL; } @@ -1094,7 +1047,8 @@ esp_auth(m0, skip, length, sav, sum) if (sizeof(sumbuf) < siz) { ipseclog((LOG_DEBUG, "esp_auth: AH_MAXSUMSIZE is too small: siz=%lu\n", - (u_long)siz)); + (u_int32_t)siz)); + KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 4,0,0,0,0); return EINVAL; } @@ -1113,26 +1067,27 @@ esp_auth(m0, skip, length, sav, sum) } error = (*algo->init)(&s, sav); - if (error) + if (error) { + KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 5,0,0,0,0); return error; - + } while (0 < length) { if (!m) panic("mbuf chain?"); if (m->m_len - off < length) { - (*algo->update)(&s, mtod(m, u_char *) + off, + (*algo->update)(&s, (caddr_t)(mtod(m, u_char *) + off), m->m_len - off); length -= m->m_len - off; m = m->m_next; off = 0; } else { - (*algo->update)(&s, mtod(m, u_char *) + off, length); + (*algo->update)(&s, (caddr_t)(mtod(m, u_char *) + off), length); break; } } - (*algo->result)(&s, sumbuf); + (*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; }