From ccbe1844343d34a87eee73ad0c2598310a5c02aa Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Mon, 13 Sep 2021 14:50:34 +0200 Subject: [PATCH] Implement CTS Ciphertext stealing on top of CBC is implemented with `wolfSSL_CRYPTO_cts128_encrypt` and `wolfSSL_CRYPTO_cts128_decrypt` APIs --- configure.ac | 2 +- src/ssl.c | 80 +++++++++++++++++++++++++++++++++++- tests/api.c | 84 ++++++++++++++++++++++++++++++++++++++ wolfssl/openssl/include.am | 1 + wolfssl/openssl/modes.h | 45 ++++++++++++++++++++ 5 files changed, 210 insertions(+), 2 deletions(-) create mode 100644 wolfssl/openssl/modes.h diff --git a/configure.ac b/configure.ac index a66067f23..f7ea2dbed 100644 --- a/configure.ac +++ b/configure.ac @@ -6815,7 +6815,7 @@ then AM_CFLAGS="-DOPENSSL_EXTRA -DWOLFSSL_ALWAYS_VERIFY_CB $AM_CFLAGS" AM_CFLAGS="-DWOLFSSL_VERIFY_CB_ALL_CERTS -DWOLFSSL_EXTRA_ALERTS $AM_CFLAGS" AM_CFLAGS="-DHAVE_EXT_CACHE -DWOLFSSL_FORCE_CACHE_ON_TICKET $AM_CFLAGS" - AM_CFLAGS="-DWOLFSSL_AKID_NAME $AM_CFLAGS" + AM_CFLAGS="-DWOLFSSL_AKID_NAME -DHAVE_CTS $AM_CFLAGS" fi if test "$ENABLED_OPENSSLEXTRA" = "x509small" diff --git a/src/ssl.c b/src/ssl.c index c255f75e8..b094b5c36 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -99,6 +99,7 @@ #include #include #include + #include #include #include #include @@ -30511,7 +30512,84 @@ int wolfSSL_AES_unwrap_key(AES_KEY *key, const unsigned char *iv, #endif /* HAVE_AES_KEYWRAP && !HAVE_FIPS && !HAVE_SELFTEST */ #endif /* NO_AES */ -#ifndef NO_ASN_TIME +#ifdef HAVE_CTS +/* + * Ciphertext stealing interface compatible with RFC2040 and RFC3962. + */ +size_t wolfSSL_CRYPTO_cts128_encrypt(const unsigned char *in, + unsigned char *out, size_t len, const void *key, + unsigned char *iv, WOLFSSL_CBC128_CB cbc) +{ + byte lastBlk[WOLFSSL_CTS128_BLOCK_SZ] = {0}; + int lastBlkLen = len % WOLFSSL_CTS128_BLOCK_SZ; + WOLFSSL_ENTER("wolfSSL_CRYPTO_cts128_encrypt"); + + if (in == NULL || out == NULL || len < WOLFSSL_CTS128_BLOCK_SZ || + cbc == NULL) { + WOLFSSL_MSG("Bad parameter"); + return WOLFSSL_FAILURE; + } + + if (lastBlkLen == 0) + lastBlkLen = WOLFSSL_CTS128_BLOCK_SZ; + + /* Encrypt data up to last block */ + (*cbc)(in, out, len - lastBlkLen, key, iv, 1); + + /* Move to last block */ + in += len - lastBlkLen; + out += len - lastBlkLen; + + /* RFC2040: Pad Pn with zeros at the end to create P of length BB. */ + XMEMCPY(lastBlk, in, lastBlkLen); + /* RFC2040: Select the first Ln bytes of En-1 to create Cn */ + XMEMCPY(out, out - WOLFSSL_CTS128_BLOCK_SZ, lastBlkLen); + (*cbc)(lastBlk, out - WOLFSSL_CTS128_BLOCK_SZ, WOLFSSL_CTS128_BLOCK_SZ, + key, iv, 1); + + return len; +} + +size_t wolfSSL_CRYPTO_cts128_decrypt(const unsigned char *in, + unsigned char *out, size_t len, const void *key, + unsigned char *iv, WOLFSSL_CBC128_CB cbc) +{ + byte lastBlk[WOLFSSL_CTS128_BLOCK_SZ] = {0}; + byte prevBlk[WOLFSSL_CTS128_BLOCK_SZ] = {0}; + int lastBlkLen = len % WOLFSSL_CTS128_BLOCK_SZ; + WOLFSSL_ENTER("wolfSSL_CRYPTO_cts128_decrypt"); + + if (in == NULL || out == NULL || len <= WOLFSSL_CTS128_BLOCK_SZ || + cbc == NULL) { + WOLFSSL_MSG("Bad parameter"); + return WOLFSSL_FAILURE; + } + + if (lastBlkLen == 0) + lastBlkLen = WOLFSSL_CTS128_BLOCK_SZ; + + /* Decrypt up to last two blocks */ + (*cbc)(in, out, len - lastBlkLen - WOLFSSL_CTS128_BLOCK_SZ, key, iv, 0); + + /* Move to last two blocks */ + in += len - lastBlkLen - WOLFSSL_CTS128_BLOCK_SZ; + out += len - lastBlkLen - WOLFSSL_CTS128_BLOCK_SZ; + + /* RFC2040: Decrypt Cn-1 to create Dn. + * Use 0 buffer as IV to do straight decryption. + * This places the Cn-1 block at lastBlk */ + (*cbc)(in, prevBlk, WOLFSSL_CTS128_BLOCK_SZ, key, lastBlk, 0); + /* RFC2040: Append the tail (BB minus Ln) bytes of Xn to Cn + * to create En. */ + XMEMCPY(prevBlk, in + WOLFSSL_CTS128_BLOCK_SZ, lastBlkLen); + /* Cn and Cn-1 can now be decrypted */ + (*cbc)(prevBlk, out, WOLFSSL_CTS128_BLOCK_SZ, key, iv, 0); + (*cbc)(lastBlk, lastBlk, WOLFSSL_CTS128_BLOCK_SZ, key, iv, 0); + XMEMCPY(out + WOLFSSL_CTS128_BLOCK_SZ, lastBlk, lastBlkLen); + return len; +} +#endif /* HAVE_CTS */ + #ifndef NO_BIO int wolfSSL_ASN1_UTCTIME_print(WOLFSSL_BIO* bio, const WOLFSSL_ASN1_UTCTIME* a) { diff --git a/tests/api.c b/tests/api.c index 274aaaa04..359cb6882 100644 --- a/tests/api.c +++ b/tests/api.c @@ -313,6 +313,7 @@ #include #include #include + #include #ifdef OPENSSL_ALL #include #include @@ -41975,6 +41976,88 @@ static void test_wolfSSL_AES_cbc_encrypt(void) #endif } +static void test_wolfSSL_CRYPTO_cts128(void) +{ +#if !defined(NO_AES) && defined(HAVE_AES_CBC) && defined(OPENSSL_EXTRA) \ + && defined(HAVE_CTS) + byte tmp[64] = {0}; /* Largest vector size */ + /* Test vectors taken form RFC3962 Appendix B */ + const testVector vects[] = { + { + "\x49\x20\x77\x6f\x75\x6c\x64\x20\x6c\x69\x6b\x65\x20\x74\x68\x65" + "\x20", + "\xc6\x35\x35\x68\xf2\xbf\x8c\xb4\xd8\xa5\x80\x36\x2d\xa7\xff\x7f" + "\x97", + 17, 17 + }, + { + "\x49\x20\x77\x6f\x75\x6c\x64\x20\x6c\x69\x6b\x65\x20\x74\x68\x65" + "\x20\x47\x65\x6e\x65\x72\x61\x6c\x20\x47\x61\x75\x27\x73\x20", + "\xfc\x00\x78\x3e\x0e\xfd\xb2\xc1\xd4\x45\xd4\xc8\xef\xf7\xed\x22" + "\x97\x68\x72\x68\xd6\xec\xcc\xc0\xc0\x7b\x25\xe2\x5e\xcf\xe5", + 31, 31 + }, + { + "\x49\x20\x77\x6f\x75\x6c\x64\x20\x6c\x69\x6b\x65\x20\x74\x68\x65" + "\x20\x47\x65\x6e\x65\x72\x61\x6c\x20\x47\x61\x75\x27\x73\x20\x43", + "\x39\x31\x25\x23\xa7\x86\x62\xd5\xbe\x7f\xcb\xcc\x98\xeb\xf5\xa8" + "\x97\x68\x72\x68\xd6\xec\xcc\xc0\xc0\x7b\x25\xe2\x5e\xcf\xe5\x84", + 32, 32 + }, + { + "\x49\x20\x77\x6f\x75\x6c\x64\x20\x6c\x69\x6b\x65\x20\x74\x68\x65" + "\x20\x47\x65\x6e\x65\x72\x61\x6c\x20\x47\x61\x75\x27\x73\x20\x43" + "\x68\x69\x63\x6b\x65\x6e\x2c\x20\x70\x6c\x65\x61\x73\x65\x2c", + "\x97\x68\x72\x68\xd6\xec\xcc\xc0\xc0\x7b\x25\xe2\x5e\xcf\xe5\x84" + "\xb3\xff\xfd\x94\x0c\x16\xa1\x8c\x1b\x55\x49\xd2\xf8\x38\x02\x9e" + "\x39\x31\x25\x23\xa7\x86\x62\xd5\xbe\x7f\xcb\xcc\x98\xeb\xf5", + 47, 47 + }, + { + "\x49\x20\x77\x6f\x75\x6c\x64\x20\x6c\x69\x6b\x65\x20\x74\x68\x65" + "\x20\x47\x65\x6e\x65\x72\x61\x6c\x20\x47\x61\x75\x27\x73\x20\x43" + "\x68\x69\x63\x6b\x65\x6e\x2c\x20\x70\x6c\x65\x61\x73\x65\x2c\x20", + "\x97\x68\x72\x68\xd6\xec\xcc\xc0\xc0\x7b\x25\xe2\x5e\xcf\xe5\x84" + "\x9d\xad\x8b\xbb\x96\xc4\xcd\xc0\x3b\xc1\x03\xe1\xa1\x94\xbb\xd8" + "\x39\x31\x25\x23\xa7\x86\x62\xd5\xbe\x7f\xcb\xcc\x98\xeb\xf5\xa8", + 48, 48 + }, + { + "\x49\x20\x77\x6f\x75\x6c\x64\x20\x6c\x69\x6b\x65\x20\x74\x68\x65" + "\x20\x47\x65\x6e\x65\x72\x61\x6c\x20\x47\x61\x75\x27\x73\x20\x43" + "\x68\x69\x63\x6b\x65\x6e\x2c\x20\x70\x6c\x65\x61\x73\x65\x2c\x20" + "\x61\x6e\x64\x20\x77\x6f\x6e\x74\x6f\x6e\x20\x73\x6f\x75\x70\x2e", + "\x97\x68\x72\x68\xd6\xec\xcc\xc0\xc0\x7b\x25\xe2\x5e\xcf\xe5\x84" + "\x39\x31\x25\x23\xa7\x86\x62\xd5\xbe\x7f\xcb\xcc\x98\xeb\xf5\xa8" + "\x48\x07\xef\xe8\x36\xee\x89\xa5\x26\x73\x0d\xbc\x2f\x7b\xc8\x40" + "\x9d\xad\x8b\xbb\x96\xc4\xcd\xc0\x3b\xc1\x03\xe1\xa1\x94\xbb\xd8", + 64, 64 + } + }; + byte keyBytes[AES_128_KEY_SIZE] = { + 0x63, 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x20, + 0x74, 0x65, 0x72, 0x69, 0x79, 0x61, 0x6b, 0x69 + }; + size_t i; + for (i = 0; i < sizeof(vects)/sizeof(vects[0]); i++) { + AES_KEY encKey; + AES_KEY decKey; + byte iv[AES_IV_SIZE] = {0}; /* All-zero IV for all cases */ + AssertIntEQ(AES_set_encrypt_key(keyBytes, AES_128_KEY_SIZE * 8, &encKey), 0); + AssertIntEQ(AES_set_decrypt_key(keyBytes, AES_128_KEY_SIZE * 8, &decKey), 0); + AssertIntEQ(CRYPTO_cts128_encrypt((const unsigned char*)vects[i].input, + tmp, vects[i].inLen, &encKey, iv, (cbc128_f)AES_cbc_encrypt), + vects[i].outLen); + AssertIntEQ(XMEMCMP(tmp, vects[i].output, vects[i].outLen), 0); + XMEMSET(iv, 0, sizeof(iv)); + AssertIntEQ(CRYPTO_cts128_decrypt((const unsigned char*)vects[i].output, + tmp, vects[i].outLen, &decKey, iv, (cbc128_f)AES_cbc_encrypt), + vects[i].inLen); + AssertIntEQ(XMEMCMP(tmp, vects[i].input, vects[i].inLen), 0); + } +#endif /* !NO_AES && HAVE_AES_CBC && OPENSSL_EXTRA && HAVE_CTS */ +} + #if defined(OPENSSL_ALL) #if !defined(NO_ASN) static void test_wolfSSL_ASN1_STRING_to_UTF8(void) @@ -51945,6 +52028,7 @@ void ApiTest(void) test_wolfSSL_DC_cert(); test_wolfSSL_DES_ncbc(); test_wolfSSL_AES_cbc_encrypt(); + test_wolfSSL_CRYPTO_cts128(); test_wolfssl_EVP_aes_gcm_AAD_2_parts(); test_wolfssl_EVP_aes_gcm(); test_wolfSSL_PKEY_up_ref(); diff --git a/wolfssl/openssl/include.am b/wolfssl/openssl/include.am index c4607966a..e1da39845 100644 --- a/wolfssl/openssl/include.am +++ b/wolfssl/openssl/include.am @@ -30,6 +30,7 @@ nobase_include_HEADERS+= \ wolfssl/openssl/lhash.h \ wolfssl/openssl/md4.h \ wolfssl/openssl/md5.h \ + wolfssl/openssl/modes.h \ wolfssl/openssl/ripemd.h \ wolfssl/openssl/obj_mac.h \ wolfssl/openssl/objects.h \ diff --git a/wolfssl/openssl/modes.h b/wolfssl/openssl/modes.h new file mode 100644 index 000000000..c1fe77217 --- /dev/null +++ b/wolfssl/openssl/modes.h @@ -0,0 +1,45 @@ +/* modes.h + * + * Copyright (C) 2006-2021 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ +#ifndef WOLFSSL_OPENSSL_MODES_H +#define WOLFSSL_OPENSSL_MODES_H + +#include +#include + +typedef void (*WOLFSSL_CBC128_CB) (const unsigned char *in, + unsigned char *out, size_t len, const void *key, + unsigned char *iv, int enc); + +WOLFSSL_API size_t wolfSSL_CRYPTO_cts128_encrypt(const unsigned char *in, + unsigned char *out, size_t len, const void *key, + unsigned char *iv, WOLFSSL_CBC128_CB cbc); +WOLFSSL_API size_t wolfSSL_CRYPTO_cts128_decrypt(const unsigned char *in, + unsigned char *out, size_t len, const void *key, + unsigned char *iv, WOLFSSL_CBC128_CB cbc); + +#define WOLFSSL_CTS128_BLOCK_SZ 16 + +/* Compatibility layer defines */ +#define CRYPTO_cts128_encrypt wolfSSL_CRYPTO_cts128_encrypt +#define CRYPTO_cts128_decrypt wolfSSL_CRYPTO_cts128_decrypt +#define cbc128_f WOLFSSL_CBC128_CB + +#endif /* WOLFSSL_OPENSSL_MODES_H */